mirror of
https://github.com/xoofx/markdig.git
synced 2026-10-08 06:38:39 +00:00
Finish SmartyPants extension (will need comments)
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
Adds support for smarty pants:
|
||||
|
||||
## SmartyPants
|
||||
## SmartyPants Quotes
|
||||
|
||||
Converts the following character to smarty pants:
|
||||
|
||||
@@ -24,6 +24,90 @@ This is a <<text>>
|
||||
<p>This is a «text»</p>
|
||||
````````````````````````````````
|
||||
|
||||
Unbalanced quotes are not changed:
|
||||
|
||||
```````````````````````````````` example
|
||||
This is a "text
|
||||
.
|
||||
<p>This is a "text</p>
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
This is a 'text
|
||||
.
|
||||
<p>This is a 'text</p>
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
This is a <<text
|
||||
.
|
||||
<p>This is a <<text</p>
|
||||
````````````````````````````````
|
||||
|
||||
Unbalanced quotes inside other quotes are not changed:
|
||||
|
||||
```````````````````````````````` example
|
||||
This is a "text 'with" a another text'
|
||||
.
|
||||
<p>This is a “text 'with” a another text'</p>
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
This is a 'text <<with' a another text>>
|
||||
.
|
||||
<p>This is a ‘text <<with’ a another text>></p>
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
This is a <<text 'with>> a another text'
|
||||
.
|
||||
<p>This is a «text 'with» a another text'</p>
|
||||
````````````````````````````````
|
||||
|
||||
Quotes requires to have the same rules than emphasis `_` regarding left/right frankling rules:
|
||||
|
||||
```````````````````````````````` example
|
||||
It's not quotes'
|
||||
.
|
||||
<p>It's not quotes'</p>
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
They are ' not matching quotes '
|
||||
.
|
||||
<p>They are ' not matching quotes '</p>
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
They are' not matching 'quotes
|
||||
.
|
||||
<p>They are' not matching 'quotes</p>
|
||||
````````````````````````````````
|
||||
|
||||
Double quotes using ``` `` ``` are working if they match another `''` pair, and there is no other double quotes on the line (otherwise they would be parsed as a code span):
|
||||
|
||||
```````````````````````````````` example
|
||||
This is ``a double quote''
|
||||
.
|
||||
<p>This is “a double quote”</p>
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
This is ``a code span''``
|
||||
.
|
||||
<p>This is <code>a code span''</code></p>
|
||||
````````````````````````````````
|
||||
|
||||
An emphasis starting inside left/right quotes will span over the right quote:
|
||||
|
||||
```````````````````````````````` example
|
||||
This is "a *text" with an emphasis*
|
||||
.
|
||||
<p>This is “a <em>text” with an emphasis</em></p>
|
||||
````````````````````````````````
|
||||
|
||||
## SmartyPants Separators
|
||||
|
||||
```````````````````````````````` example
|
||||
This is a -- text
|
||||
.
|
||||
|
||||
@@ -18439,17 +18439,17 @@ namespace Textamina.Markdig.Tests
|
||||
//
|
||||
// Adds support for smarty pants:
|
||||
//
|
||||
// ## SmartyPants
|
||||
// ## SmartyPants Quotes
|
||||
//
|
||||
// Converts the following character to smarty pants:
|
||||
[TestFixture]
|
||||
public partial class TestExtensionsSmartyPants
|
||||
public partial class TestExtensionsSmartyPantsQuotes
|
||||
{
|
||||
[Test]
|
||||
public void Example001()
|
||||
{
|
||||
// Example 1
|
||||
// Section: Extensions SmartyPants
|
||||
// Section: Extensions SmartyPants Quotes
|
||||
//
|
||||
// The following CommonMark:
|
||||
// This is a "text"
|
||||
@@ -18457,18 +18457,18 @@ namespace Textamina.Markdig.Tests
|
||||
// Should be rendered as:
|
||||
// <p>This is a “text”</p>
|
||||
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 1, "Extensions SmartyPants");
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 1, "Extensions SmartyPants Quotes");
|
||||
TestParser.TestSpec("This is a \"text\"", "<p>This is a “text”</p>", "smartypants");
|
||||
}
|
||||
}
|
||||
[TestFixture]
|
||||
public partial class TestExtensionsSmartyPants
|
||||
public partial class TestExtensionsSmartyPantsQuotes
|
||||
{
|
||||
[Test]
|
||||
public void Example002()
|
||||
{
|
||||
// Example 2
|
||||
// Section: Extensions SmartyPants
|
||||
// Section: Extensions SmartyPants Quotes
|
||||
//
|
||||
// The following CommonMark:
|
||||
// This is a 'text'
|
||||
@@ -18476,37 +18476,271 @@ namespace Textamina.Markdig.Tests
|
||||
// Should be rendered as:
|
||||
// <p>This is a ‘text’</p>
|
||||
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 2, "Extensions SmartyPants");
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 2, "Extensions SmartyPants Quotes");
|
||||
TestParser.TestSpec("This is a 'text'", "<p>This is a ‘text’</p>", "smartypants");
|
||||
}
|
||||
}
|
||||
[TestFixture]
|
||||
public partial class TestExtensionsSmartyPants
|
||||
public partial class TestExtensionsSmartyPantsQuotes
|
||||
{
|
||||
[Test]
|
||||
public void Example003()
|
||||
{
|
||||
// Example 3
|
||||
// Section: Extensions SmartyPants
|
||||
// Section: Extensions SmartyPants Quotes
|
||||
//
|
||||
// The following CommonMark:
|
||||
// This is a <<text>>
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a “text”</p>
|
||||
// <p>This is a «text»</p>
|
||||
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 3, "Extensions SmartyPants");
|
||||
TestParser.TestSpec("This is a <<text>>", "<p>This is a “text”</p>", "smartypants");
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 3, "Extensions SmartyPants Quotes");
|
||||
TestParser.TestSpec("This is a <<text>>", "<p>This is a «text»</p>", "smartypants");
|
||||
}
|
||||
}
|
||||
// Unbalanced quotes are not changed:
|
||||
[TestFixture]
|
||||
public partial class TestExtensionsSmartyPants
|
||||
public partial class TestExtensionsSmartyPantsQuotes
|
||||
{
|
||||
[Test]
|
||||
public void Example004()
|
||||
{
|
||||
// Example 4
|
||||
// Section: Extensions SmartyPants
|
||||
// Section: Extensions SmartyPants Quotes
|
||||
//
|
||||
// The following CommonMark:
|
||||
// This is a "text
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a "text</p>
|
||||
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 4, "Extensions SmartyPants Quotes");
|
||||
TestParser.TestSpec("This is a \"text", "<p>This is a "text</p>", "smartypants");
|
||||
}
|
||||
}
|
||||
[TestFixture]
|
||||
public partial class TestExtensionsSmartyPantsQuotes
|
||||
{
|
||||
[Test]
|
||||
public void Example005()
|
||||
{
|
||||
// Example 5
|
||||
// Section: Extensions SmartyPants Quotes
|
||||
//
|
||||
// The following CommonMark:
|
||||
// This is a 'text
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a 'text</p>
|
||||
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 5, "Extensions SmartyPants Quotes");
|
||||
TestParser.TestSpec("This is a 'text", "<p>This is a 'text</p>", "smartypants");
|
||||
}
|
||||
}
|
||||
[TestFixture]
|
||||
public partial class TestExtensionsSmartyPantsQuotes
|
||||
{
|
||||
[Test]
|
||||
public void Example006()
|
||||
{
|
||||
// Example 6
|
||||
// Section: Extensions SmartyPants Quotes
|
||||
//
|
||||
// The following CommonMark:
|
||||
// This is a <<text
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a <<text</p>
|
||||
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 6, "Extensions SmartyPants Quotes");
|
||||
TestParser.TestSpec("This is a <<text", "<p>This is a <<text</p>", "smartypants");
|
||||
}
|
||||
}
|
||||
// Unbalanced quotes inside other quotes are not changed:
|
||||
[TestFixture]
|
||||
public partial class TestExtensionsSmartyPantsQuotes
|
||||
{
|
||||
[Test]
|
||||
public void Example007()
|
||||
{
|
||||
// Example 7
|
||||
// Section: Extensions SmartyPants Quotes
|
||||
//
|
||||
// The following CommonMark:
|
||||
// This is a "text 'with" a another text'
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a “text 'with” a another text'</p>
|
||||
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 7, "Extensions SmartyPants Quotes");
|
||||
TestParser.TestSpec("This is a \"text 'with\" a another text'", "<p>This is a “text 'with” a another text'</p>", "smartypants");
|
||||
}
|
||||
}
|
||||
[TestFixture]
|
||||
public partial class TestExtensionsSmartyPantsQuotes
|
||||
{
|
||||
[Test]
|
||||
public void Example008()
|
||||
{
|
||||
// Example 8
|
||||
// Section: Extensions SmartyPants Quotes
|
||||
//
|
||||
// The following CommonMark:
|
||||
// This is a 'text <<with' a another text>>
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a ‘text <<with’ a another text>></p>
|
||||
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 8, "Extensions SmartyPants Quotes");
|
||||
TestParser.TestSpec("This is a 'text <<with' a another text>>", "<p>This is a ‘text <<with’ a another text>></p>", "smartypants");
|
||||
}
|
||||
}
|
||||
[TestFixture]
|
||||
public partial class TestExtensionsSmartyPantsQuotes
|
||||
{
|
||||
[Test]
|
||||
public void Example009()
|
||||
{
|
||||
// Example 9
|
||||
// Section: Extensions SmartyPants Quotes
|
||||
//
|
||||
// The following CommonMark:
|
||||
// This is a <<text 'with>> a another text'
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a «text 'with» a another text'</p>
|
||||
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 9, "Extensions SmartyPants Quotes");
|
||||
TestParser.TestSpec("This is a <<text 'with>> a another text'", "<p>This is a «text 'with» a another text'</p>", "smartypants");
|
||||
}
|
||||
}
|
||||
// Quotes requires to have the same rules than emphasis `_` regarding left/right frankling rules:
|
||||
[TestFixture]
|
||||
public partial class TestExtensionsSmartyPantsQuotes
|
||||
{
|
||||
[Test]
|
||||
public void Example010()
|
||||
{
|
||||
// Example 10
|
||||
// Section: Extensions SmartyPants Quotes
|
||||
//
|
||||
// The following CommonMark:
|
||||
// It's not quotes'
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>It's not quotes'</p>
|
||||
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 10, "Extensions SmartyPants Quotes");
|
||||
TestParser.TestSpec("It's not quotes'", "<p>It's not quotes'</p>", "smartypants");
|
||||
}
|
||||
}
|
||||
[TestFixture]
|
||||
public partial class TestExtensionsSmartyPantsQuotes
|
||||
{
|
||||
[Test]
|
||||
public void Example011()
|
||||
{
|
||||
// Example 11
|
||||
// Section: Extensions SmartyPants Quotes
|
||||
//
|
||||
// The following CommonMark:
|
||||
// They are ' not matching quotes '
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>They are ' not matching quotes '</p>
|
||||
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 11, "Extensions SmartyPants Quotes");
|
||||
TestParser.TestSpec("They are ' not matching quotes '", "<p>They are ' not matching quotes '</p>", "smartypants");
|
||||
}
|
||||
}
|
||||
[TestFixture]
|
||||
public partial class TestExtensionsSmartyPantsQuotes
|
||||
{
|
||||
[Test]
|
||||
public void Example012()
|
||||
{
|
||||
// Example 12
|
||||
// Section: Extensions SmartyPants Quotes
|
||||
//
|
||||
// The following CommonMark:
|
||||
// They are' not matching 'quotes
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>They are' not matching 'quotes</p>
|
||||
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 12, "Extensions SmartyPants Quotes");
|
||||
TestParser.TestSpec("They are' not matching 'quotes", "<p>They are' not matching 'quotes</p>", "smartypants");
|
||||
}
|
||||
}
|
||||
// Double quotes using ``` `` ``` are working if they match another `''` pair, and there is no other double quotes on the line (otherwise they would be parsed as a code span):
|
||||
[TestFixture]
|
||||
public partial class TestExtensionsSmartyPantsQuotes
|
||||
{
|
||||
[Test]
|
||||
public void Example013()
|
||||
{
|
||||
// Example 13
|
||||
// Section: Extensions SmartyPants Quotes
|
||||
//
|
||||
// The following CommonMark:
|
||||
// This is ``a double quote''
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is “a double quote”</p>
|
||||
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 13, "Extensions SmartyPants Quotes");
|
||||
TestParser.TestSpec("This is ``a double quote''", "<p>This is “a double quote”</p>", "smartypants");
|
||||
}
|
||||
}
|
||||
[TestFixture]
|
||||
public partial class TestExtensionsSmartyPantsQuotes
|
||||
{
|
||||
[Test]
|
||||
public void Example014()
|
||||
{
|
||||
// Example 14
|
||||
// Section: Extensions SmartyPants Quotes
|
||||
//
|
||||
// The following CommonMark:
|
||||
// This is ``a code span''``
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is <code>a code span''</code></p>
|
||||
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 14, "Extensions SmartyPants Quotes");
|
||||
TestParser.TestSpec("This is ``a code span''`` ", "<p>This is <code>a code span''</code></p>", "smartypants");
|
||||
}
|
||||
}
|
||||
// An emphasis starting inside left/right quotes will span over the right quote:
|
||||
[TestFixture]
|
||||
public partial class TestExtensionsSmartyPantsQuotes
|
||||
{
|
||||
[Test]
|
||||
public void Example015()
|
||||
{
|
||||
// Example 15
|
||||
// Section: Extensions SmartyPants Quotes
|
||||
//
|
||||
// The following CommonMark:
|
||||
// This is "a *text" with an emphasis*
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is “a <em>text” with an emphasis</em></p>
|
||||
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 15, "Extensions SmartyPants Quotes");
|
||||
TestParser.TestSpec("This is \"a *text\" with an emphasis*", "<p>This is “a <em>text” with an emphasis</em></p>", "smartypants");
|
||||
}
|
||||
}
|
||||
// ## SmartyPants Separators
|
||||
[TestFixture]
|
||||
public partial class TestExtensionsSmartyPantsSeparators
|
||||
{
|
||||
[Test]
|
||||
public void Example016()
|
||||
{
|
||||
// Example 16
|
||||
// Section: Extensions SmartyPants Separators
|
||||
//
|
||||
// The following CommonMark:
|
||||
// This is a -- text
|
||||
@@ -18514,18 +18748,18 @@ namespace Textamina.Markdig.Tests
|
||||
// Should be rendered as:
|
||||
// <p>This is a – text</p>
|
||||
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 4, "Extensions SmartyPants");
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 16, "Extensions SmartyPants Separators");
|
||||
TestParser.TestSpec("This is a -- text", "<p>This is a – text</p>", "smartypants");
|
||||
}
|
||||
}
|
||||
[TestFixture]
|
||||
public partial class TestExtensionsSmartyPants
|
||||
public partial class TestExtensionsSmartyPantsSeparators
|
||||
{
|
||||
[Test]
|
||||
public void Example005()
|
||||
public void Example017()
|
||||
{
|
||||
// Example 5
|
||||
// Section: Extensions SmartyPants
|
||||
// Example 17
|
||||
// Section: Extensions SmartyPants Separators
|
||||
//
|
||||
// The following CommonMark:
|
||||
// This is a --- text
|
||||
@@ -18533,18 +18767,18 @@ namespace Textamina.Markdig.Tests
|
||||
// Should be rendered as:
|
||||
// <p>This is a — text</p>
|
||||
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 5, "Extensions SmartyPants");
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 17, "Extensions SmartyPants Separators");
|
||||
TestParser.TestSpec("This is a --- text", "<p>This is a — text</p>", "smartypants");
|
||||
}
|
||||
}
|
||||
[TestFixture]
|
||||
public partial class TestExtensionsSmartyPants
|
||||
public partial class TestExtensionsSmartyPantsSeparators
|
||||
{
|
||||
[Test]
|
||||
public void Example006()
|
||||
public void Example018()
|
||||
{
|
||||
// Example 6
|
||||
// Section: Extensions SmartyPants
|
||||
// Example 18
|
||||
// Section: Extensions SmartyPants Separators
|
||||
//
|
||||
// The following CommonMark:
|
||||
// This is a en ellipsis...
|
||||
@@ -18552,7 +18786,7 @@ namespace Textamina.Markdig.Tests
|
||||
// Should be rendered as:
|
||||
// <p>This is a en ellipsis…</p>
|
||||
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 6, "Extensions SmartyPants");
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 18, "Extensions SmartyPants Separators");
|
||||
TestParser.TestSpec("This is a en ellipsis...", "<p>This is a en ellipsis…</p>", "smartypants");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
// 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 Textamina.Markdig.Renderers;
|
||||
using Textamina.Markdig.Renderers.Html;
|
||||
|
||||
namespace Textamina.Markdig.Extensions.SmartyPants
|
||||
{
|
||||
/// <summary>
|
||||
/// A HTML renderer for a <see cref="SmartyPant"/>.
|
||||
/// </summary>
|
||||
/// <seealso cref="Textamina.Markdig.Renderers.Html.HtmlObjectRenderer{SmartyPant}" />
|
||||
public class HtmlSmartyPantRenderer : HtmlObjectRenderer<SmartyPant>
|
||||
{
|
||||
private static readonly SmartyPantOptions DefaultOptions = new SmartyPantOptions();
|
||||
|
||||
private readonly SmartyPantOptions options;
|
||||
|
||||
public HtmlSmartyPantRenderer(SmartyPantOptions options)
|
||||
{
|
||||
if (options == null) throw new ArgumentNullException(nameof(options));
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
protected override void Write(HtmlRenderer renderer, SmartyPant obj)
|
||||
{
|
||||
string text;
|
||||
if (!options.Mapping.TryGetValue(obj.Type, out text))
|
||||
{
|
||||
DefaultOptions.Mapping.TryGetValue(obj.Type, out text);
|
||||
}
|
||||
renderer.Write(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
45
src/Textamina.Markdig/Extensions/SmartyPants/SmartyPant.cs
Normal file
45
src/Textamina.Markdig/Extensions/SmartyPants/SmartyPant.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
// 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 Textamina.Markdig.Syntax.Inlines;
|
||||
|
||||
namespace Textamina.Markdig.Extensions.SmartyPants
|
||||
{
|
||||
/// <summary>
|
||||
/// An inline for SmartyPant.
|
||||
/// </summary>
|
||||
[DebuggerDisplay("SmartyPant {ToLiteral()}")]
|
||||
public class SmartyPant : LeafInline
|
||||
{
|
||||
public char OpeningCharacter { get; set; }
|
||||
|
||||
public SmartyPantType Type { get; set; }
|
||||
|
||||
public string ToLiteral()
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case SmartyPantType.Quote:
|
||||
case SmartyPantType.LeftQuote:
|
||||
case SmartyPantType.RightQuote:
|
||||
return "'";
|
||||
case SmartyPantType.DoubleQuote:
|
||||
return "\"";
|
||||
case SmartyPantType.LeftDoubleQuote:
|
||||
return OpeningCharacter == '`' ? "``" : "\"";
|
||||
case SmartyPantType.RightDoubleQuote:
|
||||
return OpeningCharacter == '\'' ? "''" : "\"";
|
||||
case SmartyPantType.Dash2:
|
||||
return "--";
|
||||
case SmartyPantType.Dash3:
|
||||
return "--";
|
||||
case SmartyPantType.LeftAngleQuote:
|
||||
return "<<";
|
||||
case SmartyPantType.RightAngleQuote:
|
||||
return ">>";
|
||||
}
|
||||
return OpeningCharacter != 0 ? OpeningCharacter.ToString() : string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// See the license.txt file in the project root for more information.
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Textamina.Markdig.Extensions.SmartyPants
|
||||
{
|
||||
/// <summary>
|
||||
/// The options used for <see cref="SmartyPantsExtension"/>.
|
||||
/// </summary>
|
||||
public class SmartyPantOptions
|
||||
{
|
||||
public SmartyPantOptions()
|
||||
{
|
||||
Mapping = new Dictionary<SmartyPantType, string>()
|
||||
{
|
||||
{SmartyPantType.Quote, "'"},
|
||||
{SmartyPantType.DoubleQuote, "\""},
|
||||
{SmartyPantType.LeftQuote, "‘"},
|
||||
{SmartyPantType.RightQuote, "’"},
|
||||
{SmartyPantType.LeftDoubleQuote, "“"},
|
||||
{SmartyPantType.RightDoubleQuote, "”"},
|
||||
{SmartyPantType.LeftAngleQuote, "«"},
|
||||
{SmartyPantType.RightAngleQuote, "»"},
|
||||
{SmartyPantType.Ellipsis, "…"},
|
||||
{SmartyPantType.Dash2, "–"},
|
||||
{SmartyPantType.Dash3, "—"},
|
||||
};
|
||||
}
|
||||
|
||||
public Dictionary<SmartyPantType, string> Mapping { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// See the license.txt file in the project root for more information.
|
||||
namespace Textamina.Markdig.Extensions.SmartyPants
|
||||
{
|
||||
/// <summary>
|
||||
/// Types of a <see cref="SmartyPant"/>.
|
||||
/// </summary>
|
||||
public enum SmartyPantType
|
||||
{
|
||||
Quote = 1,
|
||||
|
||||
LeftQuote,
|
||||
|
||||
RightQuote,
|
||||
|
||||
DoubleQuote,
|
||||
|
||||
LeftDoubleQuote,
|
||||
|
||||
RightDoubleQuote,
|
||||
|
||||
LeftAngleQuote,
|
||||
|
||||
RightAngleQuote,
|
||||
|
||||
Ellipsis,
|
||||
|
||||
Dash2,
|
||||
|
||||
Dash3,
|
||||
}
|
||||
}
|
||||
@@ -2,17 +2,14 @@
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// See the license.txt file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Textamina.Markdig.Helpers;
|
||||
using Textamina.Markdig.Parsers;
|
||||
using Textamina.Markdig.Parsers.Inlines;
|
||||
using Textamina.Markdig.Renderers;
|
||||
using Textamina.Markdig.Renderers.Html;
|
||||
using Textamina.Markdig.Syntax.Inlines;
|
||||
|
||||
namespace Textamina.Markdig.Extensions.SmartyPants
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension to enable SmartyPants.
|
||||
/// </summary>
|
||||
public class SmartyPantsExtension : IMarkdownExtension
|
||||
{
|
||||
public SmartyPantsExtension(SmartyPantOptions options)
|
||||
@@ -40,319 +37,4 @@ namespace Textamina.Markdig.Extensions.SmartyPants
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum SmartyPantType
|
||||
{
|
||||
Quote,
|
||||
|
||||
LeftQuote,
|
||||
|
||||
RightQuote,
|
||||
|
||||
DoubleQuote,
|
||||
|
||||
LeftDoubleQuote,
|
||||
|
||||
RightDoubleQuote,
|
||||
|
||||
LeftAngleQuote,
|
||||
|
||||
RightAngleQuote,
|
||||
|
||||
Ellipsis,
|
||||
|
||||
Dash2,
|
||||
|
||||
Dash3,
|
||||
}
|
||||
|
||||
public class SmartyPantOptions
|
||||
{
|
||||
public SmartyPantOptions()
|
||||
{
|
||||
Mapping = new Dictionary<SmartyPantType, string>()
|
||||
{
|
||||
{SmartyPantType.Quote, "'"},
|
||||
{SmartyPantType.DoubleQuote, "\""},
|
||||
{SmartyPantType.LeftQuote, "‘"},
|
||||
{SmartyPantType.RightQuote, "’"},
|
||||
{SmartyPantType.LeftDoubleQuote, "“"},
|
||||
{SmartyPantType.RightDoubleQuote, "”"},
|
||||
{SmartyPantType.LeftAngleQuote, "«"},
|
||||
{SmartyPantType.RightAngleQuote, "»"},
|
||||
{SmartyPantType.Ellipsis, "…"},
|
||||
{SmartyPantType.Dash2, "–"},
|
||||
{SmartyPantType.Dash3, "—"},
|
||||
};
|
||||
}
|
||||
|
||||
public Dictionary<SmartyPantType, string> Mapping { get; }
|
||||
}
|
||||
|
||||
public class HtmlSmartyPantRenderer : HtmlObjectRenderer<SmartyPant>
|
||||
{
|
||||
private static readonly SmartyPantOptions DefaultOptions = new SmartyPantOptions();
|
||||
|
||||
private readonly SmartyPantOptions options;
|
||||
|
||||
public HtmlSmartyPantRenderer(SmartyPantOptions options)
|
||||
{
|
||||
if (options == null) throw new ArgumentNullException(nameof(options));
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
protected override void Write(HtmlRenderer renderer, SmartyPant obj)
|
||||
{
|
||||
string text;
|
||||
if (!options.Mapping.TryGetValue(obj.Type, out text))
|
||||
{
|
||||
DefaultOptions.Mapping.TryGetValue(obj.Type, out text);
|
||||
}
|
||||
renderer.Write(text);
|
||||
}
|
||||
}
|
||||
|
||||
public class SmartyPant : LeafInline
|
||||
{
|
||||
public char OpeningCharacter { get; set; }
|
||||
|
||||
public SmartyPantType Type { get; set; }
|
||||
}
|
||||
|
||||
public class SmaryPantsInlineParser : InlineParser
|
||||
{
|
||||
public SmaryPantsInlineParser()
|
||||
{
|
||||
OpeningCharacters = new[] {'\'', '"', '<', '>', '.', '-'};
|
||||
}
|
||||
|
||||
public override bool Match(InlineProcessor processor, ref StringSlice slice)
|
||||
{
|
||||
// We are matching the following characters:
|
||||
//
|
||||
// ' ‘ ’ ‘ ’ 'left-single-quote', 'right-single-quote'
|
||||
// '' “ ” “ ” 'left-double-quote', 'right-double-quote'
|
||||
// " “ ” “ ” 'left-double-quote', 'right-double-quote'
|
||||
// << >> « » « » 'left-angle-quote', 'right-angle-quote'
|
||||
// ... … … 'ellipsis'
|
||||
// -- – – 'ndash'
|
||||
// --- — — 'mdash'
|
||||
|
||||
var pc = slice.PeekCharExtra(-1);
|
||||
var c = slice.CurrentChar;
|
||||
var openingChar = c;
|
||||
|
||||
// undefined first
|
||||
var type = (SmartyPantType) 0;
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case '\'':
|
||||
type = SmartyPantType.Quote; // We will resolve them at the end of parsing all inlines
|
||||
if (slice.PeekChar(1) == '\'')
|
||||
{
|
||||
slice.NextChar();
|
||||
type = SmartyPantType.DoubleQuote; // We will resolve them at the end of parsing all inlines
|
||||
}
|
||||
break;
|
||||
case '"':
|
||||
type = SmartyPantType.DoubleQuote;
|
||||
break;
|
||||
case '<':
|
||||
if (slice.NextChar() == '<')
|
||||
{
|
||||
type = SmartyPantType.LeftAngleQuote;
|
||||
}
|
||||
break;
|
||||
case '>':
|
||||
if (slice.NextChar() == '>')
|
||||
{
|
||||
type = SmartyPantType.RightAngleQuote;
|
||||
}
|
||||
break;
|
||||
case '.':
|
||||
if (slice.NextChar() == '.' && slice.NextChar() == '.')
|
||||
{
|
||||
type = SmartyPantType.Ellipsis;
|
||||
}
|
||||
break;
|
||||
case '-':
|
||||
if (slice.NextChar() == '-')
|
||||
{
|
||||
type = SmartyPantType.Dash2;
|
||||
if (slice.PeekChar(1) == '-')
|
||||
{
|
||||
slice.NextChar();
|
||||
type = SmartyPantType.Dash3;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// If it is not matched, early exit
|
||||
if (type == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Skip char
|
||||
c = slice.NextChar();
|
||||
|
||||
bool canOpen;
|
||||
bool canClose;
|
||||
CharHelper.CheckOpenCloseDelimiter(pc, c, false, out canOpen, out canClose);
|
||||
|
||||
bool postProcess = false;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case SmartyPantType.Quote:
|
||||
postProcess = true;
|
||||
if (canOpen && !canClose)
|
||||
{
|
||||
type = SmartyPantType.LeftQuote;
|
||||
}
|
||||
else if (!canOpen && canClose)
|
||||
{
|
||||
type = SmartyPantType.RightQuote;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case SmartyPantType.DoubleQuote:
|
||||
postProcess = true;
|
||||
if (canOpen && !canClose)
|
||||
{
|
||||
type = SmartyPantType.LeftDoubleQuote;
|
||||
}
|
||||
else if (!canOpen && canClose)
|
||||
{
|
||||
type = SmartyPantType.RightDoubleQuote;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case SmartyPantType.LeftAngleQuote:
|
||||
postProcess = true;
|
||||
if (!canOpen || canClose)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case SmartyPantType.RightAngleQuote:
|
||||
postProcess = true;
|
||||
if (canOpen || !canClose)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case SmartyPantType.Dash2:
|
||||
case SmartyPantType.Dash3:
|
||||
if (!canOpen && !canClose)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case SmartyPantType.Ellipsis:
|
||||
if (canOpen || !canClose)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Create the SmartyPant inline
|
||||
var pant = new SmartyPant()
|
||||
{
|
||||
OpeningCharacter = openingChar,
|
||||
Type = type
|
||||
};
|
||||
|
||||
// We will check in a post-process step for balanaced open/close quotes
|
||||
if (postProcess)
|
||||
{
|
||||
var quotePants = processor.ParserStates[Index] as List<SmartyPant>;
|
||||
if (quotePants == null)
|
||||
{
|
||||
processor.ParserStates[Index] = quotePants = new List<SmartyPant>();
|
||||
}
|
||||
// Register only if we don't have yet any quotes
|
||||
if (quotePants.Count == 0)
|
||||
{
|
||||
processor.Block.ProcessInlinesEnd += BlockOnProcessInlinesEnd;
|
||||
}
|
||||
quotePants.Add(pant);
|
||||
}
|
||||
|
||||
processor.Inline = pant;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void BlockOnProcessInlinesEnd(InlineProcessor processor, Inline inline)
|
||||
{
|
||||
processor.Block.ProcessInlinesEnd -= BlockOnProcessInlinesEnd;
|
||||
|
||||
var pants = (List<SmartyPant>) processor.ParserStates[Index];
|
||||
|
||||
// We only change quote into left or right quotes if we find proper balancing
|
||||
SmartyPant previousSimpleQuote = null;
|
||||
SmartyPant previousDoubleQuote = null;
|
||||
SmartyPant previousAngleQuote = null;
|
||||
for (int i = 0; i < pants.Count; i++)
|
||||
{
|
||||
var quote = pants[i];
|
||||
|
||||
if (quote.Type == SmartyPantType.LeftQuote || quote.Type == SmartyPantType.RightQuote)
|
||||
{
|
||||
HandleLeftRight(quote, ref previousSimpleQuote, SmartyPantType.LeftQuote, SmartyPantType.RightQuote,
|
||||
"'", "'");
|
||||
}
|
||||
else if (quote.Type == SmartyPantType.LeftDoubleQuote || quote.Type == SmartyPantType.RightDoubleQuote)
|
||||
{
|
||||
var isRegularDoubleQuote = quote.OpeningCharacter == '"';
|
||||
|
||||
HandleLeftRight(quote, ref previousDoubleQuote, SmartyPantType.LeftDoubleQuote, SmartyPantType.RightDoubleQuote,
|
||||
isRegularDoubleQuote ? "\"" : "``", isRegularDoubleQuote ? "\"" : "''");
|
||||
}
|
||||
else if (quote.Type == SmartyPantType.LeftAngleQuote || quote.Type == SmartyPantType.RightAngleQuote)
|
||||
{
|
||||
HandleLeftRight(quote, ref previousAngleQuote, SmartyPantType.LeftAngleQuote, SmartyPantType.RightAngleQuote,
|
||||
"<<", ">>");
|
||||
}
|
||||
}
|
||||
|
||||
pants.Clear();
|
||||
}
|
||||
|
||||
private void HandleLeftRight(SmartyPant quote, ref SmartyPant previousQuote, SmartyPantType left, SmartyPantType right, string leftText, string rightText)
|
||||
{
|
||||
if (previousQuote == null)
|
||||
{
|
||||
if (quote.Type == left)
|
||||
{
|
||||
previousQuote = quote;
|
||||
}
|
||||
else
|
||||
{
|
||||
quote.ReplaceBy(new LiteralInline(rightText));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (quote.Type == left)
|
||||
{
|
||||
previousQuote.ReplaceBy(new LiteralInline(leftText));
|
||||
previousQuote = quote;
|
||||
}
|
||||
else
|
||||
{
|
||||
previousQuote = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,272 @@
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// See the license.txt file in the project root for more information.
|
||||
using System.Collections.Generic;
|
||||
using Textamina.Markdig.Helpers;
|
||||
using Textamina.Markdig.Parsers;
|
||||
using Textamina.Markdig.Syntax.Inlines;
|
||||
|
||||
namespace Textamina.Markdig.Extensions.SmartyPants
|
||||
{
|
||||
/// <summary>
|
||||
/// The inline parser for SmartyPants.
|
||||
/// </summary>
|
||||
public class SmaryPantsInlineParser : InlineParser
|
||||
{
|
||||
public SmaryPantsInlineParser()
|
||||
{
|
||||
OpeningCharacters = new[] {'`', '\'', '"', '<', '>', '.', '-'};
|
||||
}
|
||||
|
||||
public override bool Match(InlineProcessor processor, ref StringSlice slice)
|
||||
{
|
||||
// We are matching the following characters:
|
||||
//
|
||||
// ' ‘ ’ ‘ ’ 'left-single-quote', 'right-single-quote'
|
||||
// '' “ ” “ ” 'left-double-quote', 'right-double-quote'
|
||||
// " “ ” “ ” 'left-double-quote', 'right-double-quote'
|
||||
// << >> « » « » 'left-angle-quote', 'right-angle-quote'
|
||||
// ... … … 'ellipsis'
|
||||
// -- – – 'ndash'
|
||||
// --- — — 'mdash'
|
||||
|
||||
var pc = slice.PeekCharExtra(-1);
|
||||
var c = slice.CurrentChar;
|
||||
var openingChar = c;
|
||||
|
||||
// undefined first
|
||||
var type = (SmartyPantType) 0;
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case '`':
|
||||
if (slice.PeekChar(1) == '`')
|
||||
{
|
||||
slice.NextChar();
|
||||
type = SmartyPantType.DoubleQuote; // We will resolve them at the end of parsing all inlines
|
||||
}
|
||||
break;
|
||||
case '\'':
|
||||
type = SmartyPantType.Quote; // We will resolve them at the end of parsing all inlines
|
||||
if (slice.PeekChar(1) == '\'')
|
||||
{
|
||||
slice.NextChar();
|
||||
type = SmartyPantType.DoubleQuote; // We will resolve them at the end of parsing all inlines
|
||||
}
|
||||
break;
|
||||
case '"':
|
||||
type = SmartyPantType.DoubleQuote;
|
||||
break;
|
||||
case '<':
|
||||
if (slice.NextChar() == '<')
|
||||
{
|
||||
type = SmartyPantType.LeftAngleQuote;
|
||||
}
|
||||
break;
|
||||
case '>':
|
||||
if (slice.NextChar() == '>')
|
||||
{
|
||||
type = SmartyPantType.RightAngleQuote;
|
||||
}
|
||||
break;
|
||||
case '.':
|
||||
if (slice.NextChar() == '.' && slice.NextChar() == '.')
|
||||
{
|
||||
type = SmartyPantType.Ellipsis;
|
||||
}
|
||||
break;
|
||||
case '-':
|
||||
if (slice.NextChar() == '-')
|
||||
{
|
||||
type = SmartyPantType.Dash2;
|
||||
if (slice.PeekChar(1) == '-')
|
||||
{
|
||||
slice.NextChar();
|
||||
type = SmartyPantType.Dash3;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// If it is not matched, early exit
|
||||
if (type == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Skip char
|
||||
c = slice.NextChar();
|
||||
|
||||
bool canOpen;
|
||||
bool canClose;
|
||||
CharHelper.CheckOpenCloseDelimiter(pc, c, false, out canOpen, out canClose);
|
||||
|
||||
bool postProcess = false;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case SmartyPantType.Quote:
|
||||
postProcess = true;
|
||||
if (canOpen && !canClose)
|
||||
{
|
||||
type = SmartyPantType.LeftQuote;
|
||||
}
|
||||
else if (!canOpen && canClose)
|
||||
{
|
||||
type = SmartyPantType.RightQuote;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case SmartyPantType.DoubleQuote:
|
||||
postProcess = true;
|
||||
if (canOpen && !canClose)
|
||||
{
|
||||
type = SmartyPantType.LeftDoubleQuote;
|
||||
}
|
||||
else if (!canOpen && canClose)
|
||||
{
|
||||
type = SmartyPantType.RightDoubleQuote;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case SmartyPantType.LeftAngleQuote:
|
||||
postProcess = true;
|
||||
if (!canOpen || canClose)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case SmartyPantType.RightAngleQuote:
|
||||
postProcess = true;
|
||||
if (canOpen || !canClose)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case SmartyPantType.Ellipsis:
|
||||
if (canOpen || !canClose)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Create the SmartyPant inline
|
||||
var pant = new SmartyPant()
|
||||
{
|
||||
OpeningCharacter = openingChar,
|
||||
Type = type
|
||||
};
|
||||
|
||||
// We will check in a post-process step for balanaced open/close quotes
|
||||
if (postProcess)
|
||||
{
|
||||
var quotePants = processor.ParserStates[Index] as List<SmartyPant>;
|
||||
if (quotePants == null)
|
||||
{
|
||||
processor.ParserStates[Index] = quotePants = new List<SmartyPant>();
|
||||
}
|
||||
// Register only if we don't have yet any quotes
|
||||
if (quotePants.Count == 0)
|
||||
{
|
||||
processor.Block.ProcessInlinesEnd += BlockOnProcessInlinesEnd;
|
||||
}
|
||||
quotePants.Add(pant);
|
||||
}
|
||||
|
||||
processor.Inline = pant;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void BlockOnProcessInlinesEnd(InlineProcessor processor, Inline inline)
|
||||
{
|
||||
processor.Block.ProcessInlinesEnd -= BlockOnProcessInlinesEnd;
|
||||
|
||||
var pants = (List<SmartyPant>) 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};
|
||||
|
||||
for (int i = 0; i < pants.Count; i++)
|
||||
{
|
||||
var quote = pants[i];
|
||||
|
||||
int currentTypeIndex = -1;
|
||||
SmartyPantType expectedLeftQuote = 0;
|
||||
SmartyPantType expectedRightQuote = 0;
|
||||
|
||||
if (quote.Type == SmartyPantType.LeftQuote || quote.Type == SmartyPantType.RightQuote)
|
||||
{
|
||||
currentTypeIndex = 0;
|
||||
expectedLeftQuote = SmartyPantType.LeftQuote;
|
||||
expectedRightQuote = SmartyPantType.RightQuote;
|
||||
}
|
||||
else if (quote.Type == SmartyPantType.LeftDoubleQuote || quote.Type == SmartyPantType.RightDoubleQuote)
|
||||
{
|
||||
currentTypeIndex = 1;
|
||||
expectedLeftQuote = SmartyPantType.LeftDoubleQuote;
|
||||
expectedRightQuote = SmartyPantType.RightDoubleQuote;
|
||||
}
|
||||
else if (quote.Type == SmartyPantType.LeftAngleQuote || quote.Type == 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;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (quote.Type == expectedRightQuote)
|
||||
{
|
||||
// Replace all intermediate unmatched left or right SmartyPants to there 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.ToLiteral()));
|
||||
i--;
|
||||
}
|
||||
|
||||
// If we matched, we remove left/right quotes from the list
|
||||
pants.RemoveAt(previousIndex);
|
||||
previousIndices[currentTypeIndex] = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
previousIndices[currentTypeIndex] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we have any quotes lefts, replace them by there literal equivalent
|
||||
foreach (var quote in pants)
|
||||
{
|
||||
quote.ReplaceBy(new LiteralInline(quote.ToLiteral()));
|
||||
}
|
||||
|
||||
pants.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -45,6 +45,7 @@ namespace Textamina.Markdig
|
||||
.UseMath()
|
||||
.UseBootstrap()
|
||||
.UseMedia()
|
||||
.UseSmartyPants()
|
||||
.UseGenericAttributes(); // Must be last as it is one parser that is modifying other parsers
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user