diff --git a/src/Testamina.Markdig.Benchmarks/Program.cs b/src/Testamina.Markdig.Benchmarks/Program.cs
index 67c4022b..2f214b37 100644
--- a/src/Testamina.Markdig.Benchmarks/Program.cs
+++ b/src/Testamina.Markdig.Benchmarks/Program.cs
@@ -40,7 +40,7 @@ namespace Testamina.Markdig.Benchmarks
//CommonMark.CommonMarkConverter.Convert(new StringReader(text), new StringWriter());
//var reader = new StreamReader(File.Open("spec.md", FileMode.Open));
var reader = new StringReader(text);
- CommonMark.CommonMarkConverter.Parse(reader);
+ CommonMark.CommonMarkConverter.ProcessStage1(reader);
reader.Dispose();
}
@@ -50,8 +50,8 @@ namespace Testamina.Markdig.Benchmarks
var program = new Program();
for (int i = 0; i < 200; i++)
{
- program.TestMarkdig();
- //program.TestCommonMark();
+ //program.TestMarkdig();
+ program.TestCommonMark();
}
Console.WriteLine($"time: {clock.ElapsedMilliseconds}ms");
DumpGC();
diff --git a/src/Textamina.Markdig.Tests/TestHtmlHelper.cs b/src/Textamina.Markdig.Tests/TestHtmlHelper.cs
index 9afd812f..64fe50f9 100644
--- a/src/Textamina.Markdig.Tests/TestHtmlHelper.cs
+++ b/src/Textamina.Markdig.Tests/TestHtmlHelper.cs
@@ -14,7 +14,7 @@ namespace Textamina.Markdig.Tests
public void TestParseHtmlTagSimple()
{
var inputTag = "";
- var text = new StringLineGroup(inputTag);
+ var text = new StringSlice(inputTag);
string outputTag;
Assert.True(HtmlHelper.TryParseHtmlTag(text, out outputTag));
Assert.AreEqual(inputTag, outputTag);
@@ -24,7 +24,7 @@ namespace Textamina.Markdig.Tests
public void TestParseHtmlTagSimpleWithAttribute()
{
var inputTag = "";
- var text = new StringLineGroup(inputTag);
+ var text = new StringSlice(inputTag);
string outputTag;
Assert.True(HtmlHelper.TryParseHtmlTag(text, out outputTag));
Assert.AreEqual(inputTag, outputTag);
diff --git a/src/Textamina.Markdig.Tests/TestLinkHelper.cs b/src/Textamina.Markdig.Tests/TestLinkHelper.cs
index 59008a3f..829db282 100644
--- a/src/Textamina.Markdig.Tests/TestLinkHelper.cs
+++ b/src/Textamina.Markdig.Tests/TestLinkHelper.cs
@@ -10,9 +10,9 @@ namespace Textamina.Markdig.Tests
[Test]
public void TestUrlSimple()
{
- var text = new StringLineGroup("toto tutu");
+ var text = new StringSlice("toto tutu");
string link;
- Assert.True(LinkHelper.TryParseUrl(text, out link));
+ Assert.True(LinkHelper.TryParseUrl(ref text, out link));
Assert.AreEqual("toto", link);
Assert.AreEqual(' ', text.CurrentChar);
}
@@ -20,9 +20,9 @@ namespace Textamina.Markdig.Tests
[Test]
public void TestUrlUrl()
{
- var text = new StringLineGroup("http://google.com)");
+ var text = new StringSlice("http://google.com)");
string link;
- Assert.True(LinkHelper.TryParseUrl(text, out link));
+ Assert.True(LinkHelper.TryParseUrl(ref text, out link));
Assert.AreEqual("http://google.com", link);
Assert.AreEqual(')', text.CurrentChar);
}
@@ -30,9 +30,9 @@ namespace Textamina.Markdig.Tests
[Test]
public void TestUrlNestedParenthesis()
{
- var text = new StringLineGroup("(toto)tutu(tata) nooo");
+ var text = new StringSlice("(toto)tutu(tata) nooo");
string link;
- Assert.True(LinkHelper.TryParseUrl(text, out link));
+ Assert.True(LinkHelper.TryParseUrl(ref text, out link));
Assert.AreEqual("(toto)tutu(tata)", link);
Assert.AreEqual(' ', text.CurrentChar);
}
@@ -40,9 +40,9 @@ namespace Textamina.Markdig.Tests
[Test]
public void TestUrlAlternate()
{
- var text = new StringLineGroup(" nooo");
+ var text = new StringSlice(" nooo");
string link;
- Assert.True(LinkHelper.TryParseUrl(text, out link));
+ Assert.True(LinkHelper.TryParseUrl(ref text, out link));
Assert.AreEqual("toto_tata_tutu", link);
Assert.AreEqual(' ', text.CurrentChar);
}
@@ -50,26 +50,26 @@ namespace Textamina.Markdig.Tests
[Test]
public void TestUrlAlternateInvalid()
{
- var text = new StringLineGroup(")A");
+ var text = new StringSlice(@"(<>)A");
string link;
string title;
- Assert.True(LinkHelper.TryParseInlineLink(text, out link, out title));
+ Assert.True(LinkHelper.TryParseInlineLink(ref text, out link, out title));
Assert.AreEqual(string.Empty, link);
Assert.AreEqual(string.Empty, title);
Assert.AreEqual('A', text.CurrentChar);
@@ -101,10 +101,10 @@ namespace Textamina.Markdig.Tests
[Test]
public void TestUrlAndTitleEmpty2()
{
- var text = new StringLineGroup(@"( <> )A");
+ var text = new StringSlice(@"( <> )A");
string link;
string title;
- Assert.True(LinkHelper.TryParseInlineLink(text, out link, out title));
+ Assert.True(LinkHelper.TryParseInlineLink(ref text, out link, out title));
Assert.AreEqual(string.Empty, link);
Assert.AreEqual(string.Empty, title);
Assert.AreEqual('A', text.CurrentChar);
@@ -114,10 +114,10 @@ namespace Textamina.Markdig.Tests
[Test]
public void TestUrlEmptyWithTitleWithMultipleSpaces()
{
- var text = new StringLineGroup(@"( <> 'toto' )A");
+ var text = new StringSlice(@"( <> 'toto' )A");
string link;
string title;
- Assert.True(LinkHelper.TryParseInlineLink(text, out link, out title));
+ Assert.True(LinkHelper.TryParseInlineLink(ref text, out link, out title));
Assert.AreEqual(string.Empty, link);
Assert.AreEqual("toto", title);
Assert.AreEqual('A', text.CurrentChar);
@@ -126,10 +126,10 @@ namespace Textamina.Markdig.Tests
[Test]
public void TestUrlEmpty()
{
- var text = new StringLineGroup(@"()A");
+ var text = new StringSlice(@"()A");
string link;
string title;
- Assert.True(LinkHelper.TryParseInlineLink(text, out link, out title));
+ Assert.True(LinkHelper.TryParseInlineLink(ref text, out link, out title));
Assert.AreEqual(string.Empty, link);
Assert.AreEqual(string.Empty, title);
Assert.AreEqual('A', text.CurrentChar);
@@ -138,45 +138,41 @@ namespace Textamina.Markdig.Tests
[Test]
public void TestMultipleLines()
{
- var text = new StringLineGroup()
- {
- new StringLine("("),
- new StringLine(" "),
- new StringLine(" 'toto' )A")
- };
+ var text = new StringSlice(@"(
+
+ 'toto' )A");
string link;
string title;
- Assert.True(LinkHelper.TryParseInlineLink(text, out link, out title));
+ Assert.True(LinkHelper.TryParseInlineLink(ref text, out link, out title));
Assert.AreEqual("http://google.com", link);
Assert.AreEqual("toto", title);
Assert.AreEqual('A', text.CurrentChar);
}
-
[Test]
public void TestLabelSimple()
{
- var text = new StringLineGroup("[foo]");
+ var text = new StringSlice("[foo]");
string label;
- Assert.True(LinkHelper.TryParseLabel(text, out label));
+ Assert.True(LinkHelper.TryParseLabel(ref text, out label));
Assert.AreEqual("foo", label);
}
[Test]
public void TestLabelEscape()
{
- var text = new StringLineGroup(@"[fo\[\]o]");
+ var text = new StringSlice(@"[fo\[\]o]");
string label;
- Assert.True(LinkHelper.TryParseLabel(text, out label));
+ Assert.True(LinkHelper.TryParseLabel(ref text, out label));
Assert.AreEqual(@"fo[]o", label);
}
[Test]
public void TestLabelEscape2()
{
- var text = new StringLineGroup(@"[\]]");
+ var text = new StringSlice(@"[\]]");
string label;
- Assert.True(LinkHelper.TryParseLabel(text, out label));
+ Assert.True(LinkHelper.TryParseLabel(ref text, out label));
Assert.AreEqual(@"]", label);
}
@@ -184,31 +180,31 @@ namespace Textamina.Markdig.Tests
public void TestLabelInvalids()
{
string label;
- Assert.False(LinkHelper.TryParseLabel(new StringLineGroup(@"a"), out label));
- Assert.False(LinkHelper.TryParseLabel(new StringLineGroup(@"["), out label));
- Assert.False(LinkHelper.TryParseLabel(new StringLineGroup(@"[\x]"), out label));
- Assert.False(LinkHelper.TryParseLabel(new StringLineGroup(@"[[]"), out label));
- Assert.False(LinkHelper.TryParseLabel(new StringLineGroup(@"[ ]"), out label));
- Assert.False(LinkHelper.TryParseLabel(new StringLineGroup(@"[ \t \n ]"), out label));
+ Assert.False(LinkHelper.TryParseLabel(new StringSlice(@"a"), out label));
+ Assert.False(LinkHelper.TryParseLabel(new StringSlice(@"["), out label));
+ Assert.False(LinkHelper.TryParseLabel(new StringSlice(@"[\x]"), out label));
+ Assert.False(LinkHelper.TryParseLabel(new StringSlice(@"[[]"), out label));
+ Assert.False(LinkHelper.TryParseLabel(new StringSlice(@"[ ]"), out label));
+ Assert.False(LinkHelper.TryParseLabel(new StringSlice(@"[ \t \n ]"), out label));
}
[Test]
public void TestLabelWhitespaceCollapsedAndTrim()
{
- var text = new StringLineGroup(@"[ fo o z ]");
+ var text = new StringSlice(@"[ fo o z ]");
string label;
- Assert.True(LinkHelper.TryParseLabel(text, out label));
+ Assert.True(LinkHelper.TryParseLabel(ref text, out label));
Assert.AreEqual(@"fo o z", label);
}
[Test]
public void TestlLinkReferenceDefinitionSimple()
{
- var text = new StringLineGroup(@"[foo]: /toto 'title'");
+ var text = new StringSlice(@"[foo]: /toto 'title'");
string label;
string url;
string title;
- Assert.True(LinkHelper.TryParseLinkReferenceDefinition(text, out label, out url, out title));
+ Assert.True(LinkHelper.TryParseLinkReferenceDefinition(ref text, out label, out url, out title));
Assert.AreEqual(@"foo", label);
Assert.AreEqual(@"/toto", url);
Assert.AreEqual(@"title", title);
@@ -217,10 +213,10 @@ namespace Textamina.Markdig.Tests
[Test]
public void TestAutoLinkUrlSimple()
{
- var text = new StringLineGroup(@"");
+ var text = new StringSlice(@"");
string url;
bool isEmail;
- Assert.True(LinkHelper.TryParseAutolink(text, out url, out isEmail));
+ Assert.True(LinkHelper.TryParseAutolink(ref text, out url, out isEmail));
Assert.False(isEmail);
Assert.AreEqual("http://google.com", url);
}
@@ -228,10 +224,10 @@ namespace Textamina.Markdig.Tests
[Test]
public void TestAutoLinkEmailSimple()
{
- var text = new StringLineGroup(@"");
+ var text = new StringSlice(@"");
string email;
bool isEmail;
- Assert.True(LinkHelper.TryParseAutolink(text, out email, out isEmail));
+ Assert.True(LinkHelper.TryParseAutolink(ref text, out email, out isEmail));
Assert.True(isEmail);
Assert.AreEqual("user@host.com", email);
}
@@ -241,10 +237,10 @@ namespace Textamina.Markdig.Tests
{
string text;
bool isEmail;
- Assert.False(LinkHelper.TryParseAutolink(new StringLineGroup(@""), out text, out isEmail));
- Assert.False(LinkHelper.TryParseAutolink(new StringLineGroup(@"<"), out text, out isEmail));
- Assert.False(LinkHelper.TryParseAutolink(new StringLineGroup(@""), out text, out isEmail));
+ Assert.False(LinkHelper.TryParseAutolink(new StringSlice(@""), out text, out isEmail));
+ Assert.False(LinkHelper.TryParseAutolink(new StringSlice(@"<"), out text, out isEmail));
+ Assert.False(LinkHelper.TryParseAutolink(new StringSlice(@""), out text, out isEmail));
}
}
}
\ No newline at end of file
diff --git a/src/Textamina.Markdig.Tests/TestParser.cs b/src/Textamina.Markdig.Tests/TestParser.cs
index 0f05d94e..7380cee8 100644
--- a/src/Textamina.Markdig.Tests/TestParser.cs
+++ b/src/Textamina.Markdig.Tests/TestParser.cs
@@ -24,7 +24,7 @@ namespace Textamina.Markdig.Tests
[Test]
public void TestSimple()
{
- var reader = new StringReader(@"####### foo");
+ var reader = new StringReader(@"foo");
// var reader = new StringReader(@"> > toto tata
//> titi toto
//");
diff --git a/src/Textamina.Markdig.Tests/TestStringLine.cs b/src/Textamina.Markdig.Tests/TestStringLine.cs
index c3f96452..4331da5a 100644
--- a/src/Textamina.Markdig.Tests/TestStringLine.cs
+++ b/src/Textamina.Markdig.Tests/TestStringLine.cs
@@ -8,24 +8,25 @@ namespace Textamina.Markdig.Tests
[TestFixture]
public class TestStringLine
{
- // TODO: Add tests for StringLine
+ /*
+ // TODO: Add tests for StringSlice
// TODO: Add more tests for StringLineGroup
[Test]
public void TestStringLineGroupSimple()
{
- var text = new StringLineGroup()
+ var text = new StringSliceList()
{
- new StringLine("ABC"),
- new StringLine("E"),
- new StringLine("F")
+ new StringSlice("ABC"),
+ new StringSlice("E"),
+ new StringSlice("F")
};
var chars = ToString(text);
TextAssert.AreEqual("ABC\nE\nF", chars.ToString());
}
- private static string ToString(StringLineGroup text)
+ private static string ToString(StringSliceList text)
{
var chars = new StringBuilder();
while (text.CurrentChar != '\0')
@@ -39,10 +40,10 @@ namespace Textamina.Markdig.Tests
[Test]
public void TestStringLineGroupSaveAndRestore()
{
- var text = new StringLineGroup()
+ var text = new StringSliceList()
{
- new StringLine("ABCD"),
- new StringLine("EF"),
+ new StringSlice("ABCD"),
+ new StringSlice("EF"),
};
text.NextChar(); // B
@@ -66,7 +67,7 @@ namespace Textamina.Markdig.Tests
[Test]
public void TestSkipWhitespaces()
{
- var text = new StringLineGroup(" ABC");
+ var text = new StringSliceList(" ABC");
Assert.True(text.SkipWhiteSpaces());
Assert.False(text.SkipWhiteSpaces());
Assert.AreEqual('A', text.CurrentChar);
@@ -75,14 +76,14 @@ namespace Textamina.Markdig.Tests
[Test]
public void TestStringLineGroupWithModifiedStart()
{
- var line1 = new StringLine(" ABC");
+ var line1 = new StringSlice(" ABC");
line1.NextChar();
line1.NextChar();
- var line2 = new StringLine(" DEF ");
+ var line2 = new StringSlice(" DEF ");
line2.Trim();
- var text = new StringLineGroup() {line1, line2};
+ var text = new StringSliceList() {line1, line2};
var result = ToString(text);
TextAssert.AreEqual("ABC\nDEF", result);
@@ -92,19 +93,19 @@ namespace Textamina.Markdig.Tests
[Test]
public void TestStringLineGroupWithTrim()
{
- var line1 = new StringLine(" ABC ");
+ var line1 = new StringSlice(" ABC ");
line1.NextChar();
line1.NextChar();
- var line2 = new StringLine(" DEF ");
+ var line2 = new StringSlice(" DEF ");
- var text = new StringLineGroup() { line1, line2 };
+ var text = new StringSliceList() { line1, line2 };
text.Trim();
var result = ToString(text);
TextAssert.AreEqual("ABC \n DEF", result);
}
-
+ */
}
}
\ No newline at end of file
diff --git a/src/Textamina.Markdig/Formatters/HtmlFormatter.cs b/src/Textamina.Markdig/Formatters/HtmlFormatter.cs
index 64b98a73..88d7c916 100644
--- a/src/Textamina.Markdig/Formatters/HtmlFormatter.cs
+++ b/src/Textamina.Markdig/Formatters/HtmlFormatter.cs
@@ -26,7 +26,7 @@ namespace Textamina.Markdig.Formatters
[typeof(FencedCodeBlock)] = o => Write((FencedCodeBlock)o),
[typeof(CodeBlock)] = o => Write((CodeBlock)o),
[typeof(HeadingBlock)] = o => Write((HeadingBlock)o),
- [typeof(BreakBlock)] = o => Write((BreakBlock)o),
+ [typeof(ThematicBreakBlock)] = o => Write((ThematicBreakBlock)o),
[typeof(QuoteBlock)] = o => Write((QuoteBlock)o),
[typeof(ParagraphBlock)] = o => Write((ParagraphBlock)o),
[typeof(HtmlBlock)] = o => Write((HtmlBlock)o),
@@ -135,7 +135,7 @@ namespace Textamina.Markdig.Formatters
writer.WriteLineConstant(">");
}
- protected void Write(BreakBlock breakBlock)
+ protected void Write(ThematicBreakBlock breakBlock)
{
writer.WriteLineConstant("
");
}
@@ -282,7 +282,7 @@ namespace Textamina.Markdig.Formatters
{
writer.WriteLine();
}
- var line = lines[i];
+ var line = lines.Slices[i];
if (escape)
{
HtmlHelper.EscapeHtml(line.ToString(), writer);
diff --git a/src/Textamina.Markdig/Helpers/HtmlHelper.cs b/src/Textamina.Markdig/Helpers/HtmlHelper.cs
index e9cf58f9..84d079e9 100644
--- a/src/Textamina.Markdig/Helpers/HtmlHelper.cs
+++ b/src/Textamina.Markdig/Helpers/HtmlHelper.cs
@@ -55,16 +55,22 @@ namespace Textamina.Markdig.Helpers
"XMLRPC.BEEP", "XMLRPC.BEEPS", "XMPP", "XRI", "YMSGR", "Z39.50R", "Z39.50S"
};
- public static bool TryParseHtmlTag(StringLineGroup text, out string htmlTag)
+
+ public static bool TryParseHtmlTag(StringSlice text, out string htmlTag)
+ {
+ return TryParseHtmlTag(ref text, out htmlTag);
+ }
+
+ public static bool TryParseHtmlTag(ref StringSlice text, out string htmlTag)
{
var builder = StringBuilderCache.Local();
- var result = TryParseHtmlTag(text, builder);
+ var result = TryParseHtmlTag(ref text, builder);
htmlTag = builder.ToString();
builder.Clear();
return result;
}
- public static bool TryParseHtmlTag(StringLineGroup text, StringBuilder builder)
+ public static bool TryParseHtmlTag(ref StringSlice text, StringBuilder builder)
{
if (builder == null) throw new ArgumentNullException(nameof(builder));
var c = text.CurrentChar;
@@ -101,7 +107,7 @@ namespace Textamina.Markdig.Helpers
return TryParseHtmlTagOpenTag(text, builder);
}
- internal static bool TryParseHtmlTagOpenTag(StringLineGroup text, StringBuilder builder)
+ internal static bool TryParseHtmlTagOpenTag(StringSlice text, StringBuilder builder)
{
var c = text.CurrentChar;
@@ -256,7 +262,7 @@ namespace Textamina.Markdig.Helpers
}
}
- private static bool TryParseHtmlTagDeclaration(StringLineGroup text, StringBuilder builder)
+ private static bool TryParseHtmlTagDeclaration(StringSlice text, StringBuilder builder)
{
var c = text.CurrentChar;
bool hasAlpha = false;
@@ -291,7 +297,7 @@ namespace Textamina.Markdig.Helpers
}
}
- private static bool TryParseHtmlTagCData(StringLineGroup text, StringBuilder builder)
+ private static bool TryParseHtmlTagCData(StringSlice text, StringBuilder builder)
{
builder.Append('[');
var c = text.NextChar();
@@ -334,7 +340,7 @@ namespace Textamina.Markdig.Helpers
return false;
}
- internal static bool TryParseHtmlCloseTag(StringLineGroup text, StringBuilder builder)
+ internal static bool TryParseHtmlCloseTag(StringSlice text, StringBuilder builder)
{
// [A-Za-z][A-Za-z0-9]+\s*>
builder.Append('/');
@@ -379,7 +385,7 @@ namespace Textamina.Markdig.Helpers
}
- private static bool TryParseHtmlTagHtmlComment(StringLineGroup text, StringBuilder builder)
+ private static bool TryParseHtmlTagHtmlComment(StringSlice text, StringBuilder builder)
{
var c = text.NextChar();
if (c != '-')
@@ -388,7 +394,7 @@ namespace Textamina.Markdig.Helpers
}
builder.Append('-');
builder.Append('-');
- if (text.PeekCharOnSameLine() == '>')
+ if (text.PeekChar(1) == '>')
{
return false;
}
@@ -417,7 +423,7 @@ namespace Textamina.Markdig.Helpers
}
}
- private static bool TryParseHtmlTagProcessingInstruction(StringLineGroup text, StringBuilder builder)
+ private static bool TryParseHtmlTagProcessingInstruction(StringSlice text, StringBuilder builder)
{
builder.Append('?');
var prevChar = '\0';
diff --git a/src/Textamina.Markdig/Helpers/LinkHelper.cs b/src/Textamina.Markdig/Helpers/LinkHelper.cs
index a5017bb0..c879b772 100644
--- a/src/Textamina.Markdig/Helpers/LinkHelper.cs
+++ b/src/Textamina.Markdig/Helpers/LinkHelper.cs
@@ -8,7 +8,12 @@ namespace Textamina.Markdig.Helpers
{
public static class LinkHelper
{
- public static bool TryParseAutolink(StringLineGroup text, out string link, out bool isEmail)
+ public static bool TryParseAutolink(StringSlice text, out string link, out bool isEmail)
+ {
+ return TryParseAutolink(ref text, out link, out isEmail);
+ }
+
+ public static bool TryParseAutolink(ref StringSlice text, out string link, out bool isEmail)
{
link = null;
isEmail = false;
@@ -205,10 +210,13 @@ namespace Textamina.Markdig.Helpers
return false;
}
- public static bool TryParseInlineLink(StringLineGroup text, out string link, out string title)
+ public static bool TryParseInlineLink(StringSlice text, out string link, out string title)
{
- if (text == null) throw new ArgumentNullException(nameof(text));
+ return TryParseInlineLink(ref text, out link, out title);
+ }
+ public static bool TryParseInlineLink(ref StringSlice text, out string link, out string title)
+ {
// 1. An inline link consists of a link text followed immediately by a left parenthesis (,
// 2. optional whitespace, TODO: specs: is it whitespace or multiple whitespaces?
// 3. an optional link destination,
@@ -224,11 +232,11 @@ namespace Textamina.Markdig.Helpers
if (c == '(')
{
text.NextChar();
- text.SkipWhiteSpaces();
+ text.TrimStart();
- if (TryParseUrl(text, out link))
+ if (TryParseUrl(ref text, out link))
{
- var hasWhiteSpaces = text.SkipWhiteSpaces();
+ var hasWhiteSpaces = text.TrimStart();
c = text.CurrentChar;
if (c == ')')
@@ -242,9 +250,9 @@ namespace Textamina.Markdig.Helpers
{
isValid = true;
}
- else if (TryParseTitle(text, out title))
+ else if (TryParseTitle(ref text, out title))
{
- text.SkipWhiteSpaces();
+ text.TrimStart();
c = text.CurrentChar;
if (c == ')')
@@ -266,10 +274,13 @@ namespace Textamina.Markdig.Helpers
return isValid;
}
- public static bool TryParseTitle(StringLineGroup text, out string title)
+ public static bool TryParseTitle(StringSlice text, out string title)
{
- if (text == null) throw new ArgumentNullException(nameof(text));
+ return TryParseTitle(ref text, out title);
+ }
+ public static bool TryParseTitle(ref StringSlice text, out string title)
+ {
bool isValid = false;
var buffer = StringBuilderCache.Local();
buffer.Clear();
@@ -286,7 +297,7 @@ namespace Textamina.Markdig.Helpers
{
c = text.NextChar();
- if (text.Current != null && text.Current.IsBlankLine())
+ if (c == '\n') // TODO?
{
break;
}
@@ -333,10 +344,13 @@ namespace Textamina.Markdig.Helpers
return isValid;
}
- public static bool TryParseUrl(StringLineGroup text, out string link)
+ public static bool TryParseUrl(StringSlice text, out string link)
{
- if (text == null) throw new ArgumentNullException(nameof(text));
+ return TryParseUrl(ref text, out link);
+ }
+ public static bool TryParseUrl(ref StringSlice text, out string link)
+ {
bool isValid = false;
var buffer = StringBuilderCache.Local();
buffer.Clear();
@@ -453,12 +467,18 @@ namespace Textamina.Markdig.Helpers
return isValid;
}
- public static bool TryParseLinkReferenceDefinition(StringLineGroup text, out string label, out string url,
+ public static bool TryParseLinkReferenceDefinition(StringSlice text, out string label, out string url,
+ out string title)
+ {
+ return TryParseLinkReferenceDefinition(ref text, out label, out url, out title);
+ }
+
+ public static bool TryParseLinkReferenceDefinition(ref StringSlice text, out string label, out string url,
out string title)
{
url = null;
title = null;
- if (!TryParseLabel(text, out label))
+ if (!TryParseLabel(ref text, out label))
{
return false;
}
@@ -471,19 +491,19 @@ namespace Textamina.Markdig.Helpers
text.NextChar(); // Skip ':'
// Skip any whitespaces before the url
- text.SkipWhiteSpaces();
- if (!TryParseUrl(text, out url) || string.IsNullOrEmpty(url))
+ text.TrimStart();
+ if (!TryParseUrl(ref text, out url) || string.IsNullOrEmpty(url))
{
return false;
}
- var saved = text.Save();
+ var saved = text;
int newLineCount;
- var hasWhiteSpaces = text.SkipWhiteSpaces(out newLineCount);
+ var hasWhiteSpaces = text.TrimStart(out newLineCount);
var c = text.CurrentChar;
if (c == '\'' || c == '"' || c == '(')
{
- if (TryParseTitle(text, out title))
+ if (TryParseTitle(ref text, out title))
{
// If we have a title, it requires a whitespace after the url
if (!hasWhiteSpaces)
@@ -517,7 +537,7 @@ namespace Textamina.Markdig.Helpers
// we are still returning a valid definition
if (newLineCount > 0 && title != null)
{
- text.Restore(ref saved);
+ text = saved;
title = null;
return true;
}
@@ -531,13 +551,17 @@ namespace Textamina.Markdig.Helpers
return true;
}
- public static bool TryParseLabel(StringLineGroup lines, out string label)
+ public static bool TryParseLabel(StringSlice lines, out string label)
{
- return TryParseLabel(lines, false, out label);
+ return TryParseLabel(ref lines, false, out label);
}
+ public static bool TryParseLabel(ref StringSlice lines, out string label)
+ {
+ return TryParseLabel(ref lines, false, out label);
+ }
- public static bool TryParseLabel(StringLineGroup lines, bool allowEmpty, out string label)
+ public static bool TryParseLabel(ref StringSlice lines, bool allowEmpty, out string label)
{
label = null;
char c = lines.CurrentChar;
diff --git a/src/Textamina.Markdig/Parsing/BlockParserState.cs b/src/Textamina.Markdig/Parsing/BlockParserState.cs
index 65df64c4..ebf445f2 100644
--- a/src/Textamina.Markdig/Parsing/BlockParserState.cs
+++ b/src/Textamina.Markdig/Parsing/BlockParserState.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
+using System.Runtime.CompilerServices;
using Textamina.Markdig.Helpers;
using Textamina.Markdig.Syntax;
@@ -20,7 +21,32 @@ namespace Textamina.Markdig.Parsing
Add(root);
}
- public StringLine Line;
+
+ public StringSlice Line;
+
+ public int LineIndex;
+
+ public bool IsBlankLine => CurrentChar == '\0';
+
+ public bool IsEndOfLine => Line.IsEndOfSlice;
+
+ public char CurrentChar => Line.CurrentChar;
+
+ public char NextChar() => Line.NextChar();
+
+ public char CharAt(int index) => Line[index];
+
+ public int Start => Line.Start;
+
+ public int EndOffset => Line.End;
+
+ public int Indent => Column - ColumnBegin;
+
+ public bool IsCodeIndent => Indent >= 4;
+
+ public int ColumnBegin { get; private set; }
+
+ public int Column { get; set; }
public Block Pending { get; set; }
@@ -36,6 +62,40 @@ namespace Textamina.Markdig.Parsing
public StringBuilderCache StringBuilders { get; }
+ public char PeekChar(int offset)
+ {
+ return Line.PeekChar(offset);
+ }
+
+ [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ public void SetCurrentLine(ref StringSlice line)
+ {
+ Line = line;
+ EatSpaces();
+ }
+
+ public void EatSpaces()
+ {
+ var c = CurrentChar;
+ ColumnBegin = Column;
+ while (c !='\0')
+ {
+ if (c == ' ')
+ {
+ Column++;
+ }
+ else if (c == '\t')
+ {
+ Column = ((Column + 3) >> 2) << 2;
+ }
+ else
+ {
+ break;
+ }
+ c = NextChar();
+ }
+ }
+
public Block NextPending
{
get { return PendingIndex + 1 < Count ? this[PendingIndex + 1] : null; }
@@ -112,11 +172,5 @@ namespace Textamina.Markdig.Parsing
Close(i);
}
}
-
- internal void Reset(StringLine line)
- {
- Line = line;
- Pending = null;
- }
}
}
\ No newline at end of file
diff --git a/src/Textamina.Markdig/Parsing/InlineParserState.cs b/src/Textamina.Markdig/Parsing/InlineParserState.cs
index 7b2d71c3..d04d382e 100644
--- a/src/Textamina.Markdig/Parsing/InlineParserState.cs
+++ b/src/Textamina.Markdig/Parsing/InlineParserState.cs
@@ -16,7 +16,7 @@ namespace Textamina.Markdig.Parsing
public LeafBlock Block { get; internal set; }
- public StringLineGroup Lines;
+ public StringSlice Text;
public Inline Inline { get; set; }
diff --git a/src/Textamina.Markdig/Parsing/MarkdownParser.cs b/src/Textamina.Markdig/Parsing/MarkdownParser.cs
index 6df13b23..98737213 100644
--- a/src/Textamina.Markdig/Parsing/MarkdownParser.cs
+++ b/src/Textamina.Markdig/Parsing/MarkdownParser.cs
@@ -2,9 +2,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
-using System.Text;
using System.Threading.Tasks;
-using System.Xml.Serialization;
using Textamina.Markdig.Helpers;
using Textamina.Markdig.Syntax;
@@ -13,9 +11,6 @@ namespace Textamina.Markdig.Parsing
public class MarkdownParser
{
public static TextWriter Log;
-
- private StringLine line;
-
private readonly List blockParsers;
private readonly List inlineParsers;
private readonly List regularInlineParsers;
@@ -36,7 +31,7 @@ namespace Textamina.Markdig.Parsing
blockParserState = new BlockParserState(stringBuilderCache, document);
blockParsers = new List()
{
- BreakBlock.Parser,
+ ThematicBreakBlock.Parser,
HeadingBlock.Parser,
QuoteBlock.Parser,
ListBlock.Parser,
@@ -112,13 +107,12 @@ namespace Textamina.Markdig.Parsing
public Document Parse()
{
ParseLines();
- ProcessInlines(document);
+ //ProcessInlines(document);
return document;
}
private void ParseLines()
{
- int lineIndex = 0;
while (true)
{
var lineText = Reader.ReadLine();
@@ -128,13 +122,15 @@ namespace Textamina.Markdig.Parsing
{
break;
}
- line = new StringLine(lineText, lineIndex++);
+ var line = new StringSlice(lineText);
+ blockParserState.SetCurrentLine(ref line);
+ blockParserState.LineIndex++;
bool continueProcessLiner = ProcessPendingBlocks();
// If we have already reached eol and the last block was a paragraph
// we close it
- if (line.IsEol)
+ if (blockParserState.Line.IsEndOfSlice)
{
int index = blockParserState.Count - 1;
if (blockParserState[index] is ParagraphBlock)
@@ -203,7 +199,7 @@ namespace Textamina.Markdig.Parsing
}
// Create the line state that will be used by all parser
- blockParserState.Reset(line);
+ blockParserState.Pending = null;
// Process any current block potentially opened
for (int i = 1; i < blockParserState.Count; i++)
@@ -220,7 +216,7 @@ namespace Textamina.Markdig.Parsing
break;
}
- var saveLiner = line.Save();
+ var saveLiner = blockParserState.Line;
// If we have a discard, we can remove it from the current state
blockParserState.CurrentContainer = LastContainer;
@@ -235,7 +231,7 @@ namespace Textamina.Markdig.Parsing
if (result == MatchLineResult.None)
{
// Restore the Line where it was
- line.Restore(ref saveLiner);
+ blockParserState.SetCurrentLine(ref saveLiner);
break;
}
@@ -258,7 +254,7 @@ namespace Textamina.Markdig.Parsing
processLiner = false;
if (result != MatchLineResult.LastDiscard && result != MatchLineResult.ContinueDiscard)
{
- leaf.Append(line);
+ leaf.Lines.Append(ref blockParserState.Line);
}
if (blockParserState.NewBlocks.Count > 0)
@@ -294,12 +290,12 @@ namespace Textamina.Markdig.Parsing
private void ParseNewBlocks(ref bool continueProcessLiner)
{
- blockParserState.Reset(line);
+ blockParserState.Pending = null;
for (int j = 0; j < blockParsers.Count; j++)
{
var blockParser = blockParsers[j];
- if (line.IsEol)
+ if (blockParserState.Line.IsEndOfSlice)
{
continueProcessLiner = false;
break;
@@ -319,19 +315,19 @@ namespace Textamina.Markdig.Parsing
blockParserState.CurrentContainer = LastContainer;
blockParserState.LastBlock = lastBlock;
- var saveLiner = line.Save();
+ var saveLiner = blockParserState.Line;
var result = blockParser.Match(blockParserState);
if (result == MatchLineResult.None)
{
// If we have reached a blank line after trying to parse a paragraph
// we can ignore it
- if (isParsingParagraph && line.IsBlankLine())
+ if (isParsingParagraph && blockParserState.IsBlankLine)
{
continueProcessLiner = false;
break;
}
- line.Restore(ref saveLiner);
+ blockParserState.SetCurrentLine(ref saveLiner);
continue;
}
@@ -342,7 +338,7 @@ namespace Textamina.Markdig.Parsing
Debug.Assert(blockParserState.NewBlocks.Count == 0);
continueProcessLiner = false;
- paragraph.Append(line);
+ paragraph.Lines.Append(ref blockParserState.Line);
// We have just found a lazy continuation for a paragraph, early exit
// Mark all block opened after a lazy continuation
@@ -383,7 +379,7 @@ namespace Textamina.Markdig.Parsing
{
var block = newBlocks.Pop();
- block.Line = line.LineIndex;
+ block.Line = blockParserState.LineIndex;
// If we have a leaf block
var leaf = block as LeafBlock;
@@ -391,7 +387,7 @@ namespace Textamina.Markdig.Parsing
{
if (result != MatchLineResult.LastDiscard && result != MatchLineResult.ContinueDiscard)
{
- leaf.Append(line);
+ leaf.Lines.Append(ref blockParserState.Line);
}
if (newBlocks.Count > 0)
@@ -433,28 +429,25 @@ namespace Textamina.Markdig.Parsing
var lines = leafBlock.Lines;
leafBlock.Inline = new ContainerInline() {IsClosed = false};
- var inlineState = new InlineParserState(stringBuilderCache, document);
-
- inlineState.Lines = lines;
- inlineState.Inline = leafBlock.Inline;
- inlineState.Block = leafBlock;
-
- var saveLines = new StringLineGroup.State();
-
- while (!lines.IsEndOfLines)
+ var inlineState = new InlineParserState(stringBuilderCache, document)
{
- lines.Save(ref saveLines);
+ Text = new StringSlice(leafBlock.Lines.ToString()),
+ Inline = leafBlock.Inline,
+ Block = leafBlock
+ };
- var c = lines.CurrentChar;
+ while (!inlineState.Text.IsEndOfSlice)
+ {
+ var saveLine = inlineState.Text;
+
+ var c = saveLine.CurrentChar;
var inlineParser = c < 128 ? inlineWithFirstCharParsers[c] : null;
if (inlineParser == null || !inlineParser.Match(inlineState))
{
for (int i = 0; i < regularInlineParsers.Count; i++)
{
- lines.Restore(ref saveLines);
-
+ inlineState.Text = saveLine;
inlineParser = regularInlineParsers[i];
-
if (inlineParser.Match(inlineState))
{
break;
@@ -465,7 +458,7 @@ namespace Textamina.Markdig.Parsing
if (inlineParser == null)
{
- lines.Restore(ref saveLines);
+ inlineState.Text = saveLine;
}
}
diff --git a/src/Textamina.Markdig/Syntax/CodeBlock.cs b/src/Textamina.Markdig/Syntax/CodeBlock.cs
index 6fe403a4..3cac7a8b 100644
--- a/src/Textamina.Markdig/Syntax/CodeBlock.cs
+++ b/src/Textamina.Markdig/Syntax/CodeBlock.cs
@@ -1,5 +1,3 @@
-using System;
-using Textamina.Markdig.Helpers;
using Textamina.Markdig.Parsing;
namespace Textamina.Markdig.Syntax
@@ -28,56 +26,15 @@ namespace Textamina.Markdig.Syntax
public override MatchLineResult Match(BlockParserState state)
{
- var liner = state.Line;
- int position = liner.Start;
- liner.SkipLeadingSpaces3();
-
- // 4.4 Indented code blocks
- var c = liner.Current;
- var isTab = c.IsTab();
- var isSpace = c.IsSpace();
- var isBlankLine = liner.IsBlankLine();
- var codeBlock = state.Pending as CodeBlock;
- // && !isBlankLine) || (isBlankLine && codeBlock != null && !codeBlock.Lines[codeBlock.Lines.Count - 1].IsBlankLine())
- if ((codeBlock != null && isBlankLine) || (isTab || (isSpace && (liner.Start - position) == 3)))
- //if (((isTab || (isSpace && (liner.Start - position) == 3)) && !isBlankLine))
+ if (!state.IsCodeIndent || state.IsBlankLine)
{
- liner.NextChar();
- if (state.Pending == null)
- {
- if (isBlankLine)
- {
- return MatchLineResult.None;
- }
-
- state.NewBlocks.Push(new CodeBlock(this) { Column = position });
- }
- return MatchLineResult.Continue;
+ return state.IsBlankLine && state.Pending != null ? MatchLineResult.LastDiscard : MatchLineResult.None;
}
-
- return MatchLineResult.None;
- }
-
- public override void Close(BlockParserState state)
- {
- var codeBlock = state.Pending as CodeBlock;
- if (codeBlock != null)
+ if (state.Pending == null)
{
- var lines = codeBlock.Lines;
- // Remove trailing blankline
- for (int i = lines.Count - 1; i >= 0; i--)
- {
- if (lines[i].IsBlankLine())
- {
- lines.RemoveAt(i);
- }
- else
- {
- break;
- }
- }
+ state.NewBlocks.Push(new CodeBlock(this) { Column = state.Column });
}
-
+ return MatchLineResult.Continue;
}
}
}
diff --git a/src/Textamina.Markdig/Syntax/FencedCodeBlock.cs b/src/Textamina.Markdig/Syntax/FencedCodeBlock.cs
index 3b59790d..1e7c3100 100644
--- a/src/Textamina.Markdig/Syntax/FencedCodeBlock.cs
+++ b/src/Textamina.Markdig/Syntax/FencedCodeBlock.cs
@@ -34,149 +34,148 @@ namespace Textamina.Markdig.Syntax
{
public override MatchLineResult Match(BlockParserState state)
{
- var liner = state.Line;
+ int count;
+ char matchChar;
+ char c = state.CurrentChar;
+ int offset = 0;
- var fenced = state.Pending as FencedCodeBlock;
- if (fenced != null)
+ var currentFenced = state.Pending as FencedCodeBlock;
+ if (currentFenced != null)
{
- var saveLiner = liner.Save();
- liner.SkipLeadingSpaces3();
-
- var c = liner.Current;
- int count = fenced.fencedCharCount;
- var matchChar = fenced.fencedChar;
- while (!liner.IsEol)
+ count = currentFenced.fencedCharCount;
+ matchChar = currentFenced.fencedChar;
+ while (c == matchChar)
{
- if (c != matchChar)
- {
- break;
- }
- c = liner.NextChar();
- count--;
+ offset++;
+ c = state.Line.PeekChar(offset);
}
- if (count <= 0)
+ if (offset >= count)
{
- int endPosition = liner.Start;
- liner.TrimEnd(true);
- if (liner.IsEol || liner.End == endPosition)
+ state.Line.TrimEnd(true);
+ if (state.CurrentChar == matchChar)
{
return MatchLineResult.LastDiscard;
}
}
- liner.Restore(ref saveLiner);
-
// TODO: It is unclear how to handle this correctly
// Break only if Eof
return MatchLineResult.Continue;
}
- else
- {
- // TODO: We need to count the number of leading space to remove them on each line
- var start = liner.Start;
- liner.SkipLeadingSpaces3();
- var column = liner.Start;
- var indentCount = liner.Start - start;
- var c = liner.Current;
- int count = 0;
- var matchChar = (char)0;
- while (!liner.IsEol)
+ // Else if the we have an indent, it is not valid
+ if (state.IsCodeIndent)
+ {
+ return MatchLineResult.None;
+ }
+
+ count = 0;
+ matchChar = (char) 0;
+ while (c != '\0')
+ {
+ if (count == 0 && (c == '`' || c == '~'))
{
- if (count == 0 && (c == '`' || c == '~'))
- {
- matchChar = c;
- }
- else if (c != matchChar)
- {
- break;
- }
- c = liner.NextChar();
- count++;
+ matchChar = c;
+ }
+ else if (c != matchChar)
+ {
+ break;
+ }
+ count++;
+ c = state.PeekChar(count);
+ }
+
+ if (count >= 3)
+ {
+ return MatchLineResult.None;
+ }
+
+ // TODO: We need to count the number of leading space to remove them on each line
+ var column = state.Column;
+
+ // specs spaces: Is space and tabs? or only spaces? Use space and tab for this case
+ while (c.IsSpaceOrTab())
+ {
+ offset++;
+ c = state.PeekChar(offset);
+ }
+ var start = state.Start + count + offset;
+
+ string infoString;
+ string argString = null;
+
+ // An info string cannot contain any backsticks
+ int firstSpace = -1;
+ for (int i = start; i <= state.EndOffset; i++)
+ {
+ c = state.Line[i];
+ if (c == '`')
+ {
+ return MatchLineResult.None;
}
- if (count >= 3)
+ if (firstSpace < 0 && c.IsSpaceOrTab())
{
- // specs spaces: Is space and tabs? or only spaces? Use space and tab for this case
- liner.TrimStart(true);
- liner.TrimEnd(true);
+ firstSpace = i;
+ }
+ }
- string infoString = null;
- string argString = null;
+ if (firstSpace > 0)
+ {
+ infoString = state.Line.Text.Substring(start, firstSpace - start);
- // An info string cannot contain any backsticks
- int firstSpace = -1;
- for (int i = liner.Start; i <= liner.End; i++)
+ // Skip any spaces after info string
+ firstSpace++;
+ while (true)
+ {
+ c = state.Line[firstSpace];
+ if (c.IsSpaceOrTab())
{
- c = liner[i];
- if (c == '`')
- {
- return MatchLineResult.None;
- }
- else if (firstSpace < 0 && c.IsSpaceOrTab())
- {
- firstSpace = i;
- }
- }
-
- if (firstSpace > 0)
- {
- infoString = liner.Text.Substring(liner.Start, firstSpace - liner.Start);
-
- // Skip any spaces after info string
firstSpace++;
- while (true)
- {
- c = liner[firstSpace];
- if (c.IsSpaceOrTab())
- {
- firstSpace++;
- }
- else
- {
- break;
- }
- }
-
- argString = liner.Text.Substring(firstSpace, liner.End - firstSpace + 1);
}
else
{
- infoString = liner.ToString();
+ break;
}
-
- // Store the number of matched string into the context
- state.NewBlocks.Push(new FencedCodeBlock(this)
- {
- Column = column,
- fencedChar = matchChar,
- fencedCharCount = count,
- indentCount = indentCount,
- Language = HtmlHelper.Unescape(infoString),
- Arguments = HtmlHelper.Unescape(argString),
- });
- return MatchLineResult.ContinueDiscard;
}
- return MatchLineResult.None;
+ argString = state.Line.Text.Substring(firstSpace, state.Line.End - firstSpace + 1);
}
+ else
+ {
+ infoString = state.Line.Text.Substring(start, state.EndOffset - start + 1);
+ }
+
+ // Store the number of matched string into the context
+ state.NewBlocks.Push(new FencedCodeBlock(this)
+ {
+ Column = column,
+ fencedChar = matchChar,
+ fencedCharCount = count,
+ indentCount = state.Indent,
+ Language = HtmlHelper.Unescape(infoString),
+ Arguments = HtmlHelper.Unescape(argString),
+ });
+
+ // Discard the current line
+ return MatchLineResult.ContinueDiscard;
}
public override void Close(BlockParserState state)
{
- var fenced = (FencedCodeBlock) state.Pending;
- for (int i = 0; i < fenced.Lines.Count; i++)
+ var fenced = ((FencedCodeBlock) state.Pending);
+ var lines = fenced.Lines;
+ for (int i = 0; i < lines.Count; i++)
{
- var line = fenced.Lines[i];
-
// Fences can be indented. If the opening fence is indented,
// content lines will have equivalent opening indentation removed, if present:
for (int j = 0; j < fenced.indentCount; j++)
{
- if (line.Start < line.End && line[line.Start].IsSpace())
+ var start = lines.Slices[i].Start;
+ if (start < lines.Slices[i].End && lines.Slices[i][start].IsSpace())
{
- line.Start++;
+ lines.Slices[i].Start++;
}
else
{
diff --git a/src/Textamina.Markdig/Syntax/HeadingBlock.cs b/src/Textamina.Markdig/Syntax/HeadingBlock.cs
index e8d60bea..f046d711 100644
--- a/src/Textamina.Markdig/Syntax/HeadingBlock.cs
+++ b/src/Textamina.Markdig/Syntax/HeadingBlock.cs
@@ -20,10 +20,10 @@ namespace Textamina.Markdig.Syntax
{
public override MatchLineResult Match(BlockParserState state)
{
- var liner = state.Line;
- liner.SkipLeadingSpaces3();
-
- var column = liner.Start;
+ if (state.IsCodeIndent)
+ {
+ return MatchLineResult.None;
+ }
// 4.2 ATX headings
// An ATX heading consists of a string of characters, parsed as inline content,
@@ -35,37 +35,37 @@ namespace Textamina.Markdig.Syntax
// the heading are stripped of leading and trailing spaces before being parsed as
// inline content. The heading level is equal to the number of # characters in the
// opening sequence.
- var c = liner.Current;
+ var column = state.Column;
+ var c = state.CurrentChar;
int leadingCount = 0;
- for (; !liner.IsEol && leadingCount <= 6; leadingCount++)
+ for (; !state.Line.IsEndOfSlice && leadingCount <= 6; leadingCount++)
{
if (c != '#')
{
break;
}
- c = liner.NextChar();
+ c = state.PeekChar(leadingCount);
}
// closing # will be handled later, because anyway we have matched
// A space is required after leading #
- if (leadingCount > 0 && leadingCount <=6 && (c.IsSpace() || liner.IsEol))
+ if (leadingCount > 0 && leadingCount <=6 && (c.IsSpace() || state.Line.IsEndOfSlice))
{
- liner.NextChar();
+ state.Line.Start = leadingCount + 1;
state.NewBlocks.Push(new HeadingBlock(this) {Level = leadingCount, Column = column });
-
// The optional closing sequence of #s must be preceded by a space and may be followed by spaces only.
int endState = 0;
int countClosingTags = 0;
- for (int i = liner.End; i >= liner.Start - 1; i--) // Go up to Start - 1 in order to match the space after the first ###
+ for (int i = state.Line.End; i >= state.Line.Start - 1; i--) // Go up to Start - 1 in order to match the space after the first ###
{
- c = liner[i];
+ c = state.Line[i];
if (endState == 0)
{
- if (CharHelper.IsSpace(c)) // TODO: Not clear if it is a space or space+tab in the specs
+ if (c.IsSpace()) // TODO: Not clear if it is a space or space+tab in the specs
{
continue;
}
@@ -81,9 +81,9 @@ namespace Textamina.Markdig.Syntax
if (countClosingTags > 0)
{
- if (CharHelper.IsSpace(c))
+ if (c.IsSpace())
{
- liner.End = i - 1;
+ state.Line.End = i - 1;
}
break;
}
diff --git a/src/Textamina.Markdig/Syntax/HtmlBlock.cs b/src/Textamina.Markdig/Syntax/HtmlBlock.cs
index d68fceed..6becd456 100644
--- a/src/Textamina.Markdig/Syntax/HtmlBlock.cs
+++ b/src/Textamina.Markdig/Syntax/HtmlBlock.cs
@@ -16,10 +16,6 @@ namespace Textamina.Markdig.Syntax
public HtmlBlockType Type { get; set; }
- [ThreadStatic]
- private static readonly StringLineGroup HtmlLineGroup = new StringLineGroup();
-
-
private class ParserInternal : BlockParser
{
private static readonly string[] HtmlTags =
@@ -106,12 +102,11 @@ namespace Textamina.Markdig.Syntax
private MatchLineResult MatchStart(BlockParserState state)
{
- var liner = state.Line;
int index = 0;
for (int i = 0; i < 3; i++)
{
- if (!liner.PeekChar(index).IsSpace())
+ if (!state.Line.PeekChar(index).IsSpace())
{
break;
}
@@ -120,36 +115,34 @@ namespace Textamina.Markdig.Syntax
// Early exit if it is not starting by an HTML tag
var column = index;
- var c = liner.PeekChar(index++);
+ var c = state.Line.PeekChar(index++);
if (c != '<')
{
return MatchLineResult.None;
}
- var result = TryParseTagType16(state, liner, index, column);
+ var result = TryParseTagType16(state, ref state.Line, index, column);
// HTML blocks of type 7 cannot interrupt a paragraph:
if (result == MatchLineResult.None && !(state.LastBlock is ParagraphBlock))
{
- result = TryParseTagType7(state, liner, index, column);
+ result = TryParseTagType7(state, ref state.Line, index, column);
}
return result;
}
- private MatchLineResult TryParseTagType7(BlockParserState state, StringLine liner, int index, int startColumn)
+ private MatchLineResult TryParseTagType7(BlockParserState state, ref StringSlice liner, int index, int startColumn)
{
var builder = StringBuilderCache.Local();
- var text = HtmlLineGroup;
- text.Add(liner);
- text.SetColumn(index);
- var c = text.CurrentChar;
+ liner.Start = index;
+ var c = liner.CurrentChar;
var result = MatchLineResult.None;
- if ((c == '/' && HtmlHelper.TryParseHtmlCloseTag(text, builder)) || HtmlHelper.TryParseHtmlTagOpenTag(text, builder))
+ if ((c == '/' && HtmlHelper.TryParseHtmlCloseTag(liner, builder)) || HtmlHelper.TryParseHtmlTagOpenTag(liner, builder))
{
// Must be followed by whitespace only
bool hasOnlySpaces = true;
- c = text.CurrentChar;
+ c = liner.CurrentChar;
while (true)
{
if (c == '\0')
@@ -161,7 +154,7 @@ namespace Textamina.Markdig.Syntax
hasOnlySpaces = false;
break;
}
- c = text.NextChar();
+ c = liner.NextChar();
}
if (hasOnlySpaces)
@@ -170,12 +163,11 @@ namespace Textamina.Markdig.Syntax
}
}
- text.Clear();
builder.Clear();
return result;
}
- private MatchLineResult TryParseTagType16(BlockParserState state, StringLine liner, int index, int startColumn)
+ private MatchLineResult TryParseTagType16(BlockParserState state, ref StringSlice liner, int index, int startColumn)
{
char c;
c = liner.PeekChar(index);
@@ -255,51 +247,49 @@ namespace Textamina.Markdig.Syntax
private MatchLineResult MatchEnd(BlockParserState state, HtmlBlock htmlBlock)
{
- var liner = state.Line;
-
// Early exit if it is not starting by an HTML tag
- var c = liner.Current;
+ var c = state.Line.CurrentChar;
switch (htmlBlock.Type)
{
case HtmlBlockType.Comment:
- if (liner.Search("-->"))
+ if (state.Line.Search("-->"))
{
return MatchLineResult.Last;
}
break;
case HtmlBlockType.CData:
- if (liner.Search("]]>"))
+ if (state.Line.Search("]]>"))
{
return MatchLineResult.Last;
}
break;
case HtmlBlockType.ProcessingInstruction:
- if (liner.Search("?>"))
+ if (state.Line.Search("?>"))
{
return MatchLineResult.Last;
}
break;
case HtmlBlockType.DocumentType:
- if (liner.Search(">"))
+ if (state.Line.Search(">"))
{
return MatchLineResult.Last;
}
break;
case HtmlBlockType.ScriptPreOrStyle:
// TODO: could be optimized with a dedicated parser
- if (liner.SearchLowercase("") || liner.SearchLowercase("") || liner.SearchLowercase(""))
+ if (state.Line.SearchLowercase("") || state.Line.SearchLowercase("") || state.Line.SearchLowercase(""))
{
return MatchLineResult.Last;
}
break;
case HtmlBlockType.InterruptingBlock:
- if (liner.IsBlankLine())
+ if (state.IsBlankLine)
{
return MatchLineResult.LastDiscard;
}
break;
case HtmlBlockType.NonInterruptingBlock:
- if (liner.IsBlankLine())
+ if (state.IsBlankLine)
{
return MatchLineResult.LastDiscard;
}
diff --git a/src/Textamina.Markdig/Syntax/Inlines/AutoLinkInline.cs b/src/Textamina.Markdig/Syntax/Inlines/AutoLinkInline.cs
index 3dd5037d..784acf5a 100644
--- a/src/Textamina.Markdig/Syntax/Inlines/AutoLinkInline.cs
+++ b/src/Textamina.Markdig/Syntax/Inlines/AutoLinkInline.cs
@@ -20,20 +20,18 @@ namespace Textamina.Markdig.Syntax
public override bool Match(InlineParserState state)
{
- var text = state.Lines;
-
string link;
bool isEmail;
- var saved = text.Save();
- if (LinkHelper.TryParseAutolink(text, out link, out isEmail))
+ var saved = state.Text;
+ if (LinkHelper.TryParseAutolink(ref state.Text, out link, out isEmail))
{
state.Inline = new AutolinkInline() {IsEmail = isEmail, Url = link};
}
else
{
- text.Restore(ref saved);
+ state.Text = saved;
string htmlTag;
- if (!HtmlHelper.TryParseHtmlTag(text, out htmlTag))
+ if (!HtmlHelper.TryParseHtmlTag(ref state.Text, out htmlTag))
{
return false;
}
diff --git a/src/Textamina.Markdig/Syntax/Inlines/CodeInline.cs b/src/Textamina.Markdig/Syntax/Inlines/CodeInline.cs
index 84cf0416..d05cd209 100644
--- a/src/Textamina.Markdig/Syntax/Inlines/CodeInline.cs
+++ b/src/Textamina.Markdig/Syntax/Inlines/CodeInline.cs
@@ -18,10 +18,10 @@ namespace Textamina.Markdig.Syntax
public override bool Match(InlineParserState state)
{
- var text = state.Lines;
+ var text = state.Text;
int openSticks = 0;
- if (text.PreviousChar1 == '`')
+ if (text.PeekChar(-1) == '`')
{
return false;
}
diff --git a/src/Textamina.Markdig/Syntax/Inlines/EmphasisInline.cs b/src/Textamina.Markdig/Syntax/Inlines/EmphasisInline.cs
index 374a0b00..063e604b 100644
--- a/src/Textamina.Markdig/Syntax/Inlines/EmphasisInline.cs
+++ b/src/Textamina.Markdig/Syntax/Inlines/EmphasisInline.cs
@@ -215,15 +215,13 @@ namespace Textamina.Markdig.Syntax
public override bool Match(InlineParserState state)
{
- var lines = state.Lines;
-
// First, some definitions. A delimiter run is either a sequence of one or more * characters that
// is not preceded or followed by a * character, or a sequence of one or more _ characters that
// is not preceded or followed by a _ character.
- var delimiterChar = lines.CurrentChar;
- var pc = lines.PreviousChar1;
- if (delimiterChar == pc && lines.PreviousChar2 != '\\')
+ var delimiterChar = state.Text.CurrentChar;
+ var pc = state.Text.PeekChar(-1);
+ if (delimiterChar == pc && state.Text.PeekChar(-2) != '\\')
{
return false;
}
@@ -233,7 +231,7 @@ namespace Textamina.Markdig.Syntax
do
{
delimiterCount++;
- c = lines.NextChar();
+ c = state.Text.NextChar();
} while (c == delimiterChar);
diff --git a/src/Textamina.Markdig/Syntax/Inlines/EscapeInline.cs b/src/Textamina.Markdig/Syntax/Inlines/EscapeInline.cs
index 644a2718..0869d214 100644
--- a/src/Textamina.Markdig/Syntax/Inlines/EscapeInline.cs
+++ b/src/Textamina.Markdig/Syntax/Inlines/EscapeInline.cs
@@ -20,7 +20,7 @@ namespace Textamina.Markdig.Syntax
public override bool Match(InlineParserState state)
{
- var lines = state.Lines;
+ var lines = state.Text;
// Go to escape character
lines.NextChar();
diff --git a/src/Textamina.Markdig/Syntax/Inlines/HardlineBreakInline.cs b/src/Textamina.Markdig/Syntax/Inlines/HardlineBreakInline.cs
index 6dcca1af..322605fc 100644
--- a/src/Textamina.Markdig/Syntax/Inlines/HardlineBreakInline.cs
+++ b/src/Textamina.Markdig/Syntax/Inlines/HardlineBreakInline.cs
@@ -17,8 +17,7 @@ namespace Textamina.Markdig.Syntax
public override bool Match(InlineParserState state)
{
// Hard line breaks are for separating inline content within a block. Neither syntax for hard line breaks works at the end of a paragraph or other block element:
- var text = state.Lines;
- if (!(state.Block is ParagraphBlock) || text.ColumnPosition == 0 || !text.PreviousChar1.IsSpace() || !text.PreviousChar2.IsSpace())
+ if (!(state.Block is ParagraphBlock) || state.Text.Column == 0 || !state.Text.PeekChar(-1).IsSpace() || !state.Text.PeekChar(-2).IsSpace())
{
return false;
}
diff --git a/src/Textamina.Markdig/Syntax/Inlines/LinkInline.cs b/src/Textamina.Markdig/Syntax/Inlines/LinkInline.cs
index 2d9320cb..8a001cc4 100644
--- a/src/Textamina.Markdig/Syntax/Inlines/LinkInline.cs
+++ b/src/Textamina.Markdig/Syntax/Inlines/LinkInline.cs
@@ -30,15 +30,13 @@ namespace Textamina.Markdig.Syntax
public override bool Match(InlineParserState state)
{
- var text = state.Lines;
-
- var c = text.CurrentChar;
+ var c = state.Text.CurrentChar;
bool isImage = false;
if (c == '!')
{
isImage = true;
- c = text.NextChar();
+ c = state.Text.NextChar();
if (c != '[')
{
return false;
@@ -50,21 +48,21 @@ namespace Textamina.Markdig.Syntax
case '[':
// If this is not an image, we may have a reference link shortcut
// so we try to resolve it here
- var saved = text.Save();
+ var saved = state.Text;
string label;
// If the label is followed by either a ( or a [, this is not a shortcut
- if (LinkHelper.TryParseLabel(text, out label))
+ if (LinkHelper.TryParseLabel(ref state.Text, out label))
{
if (!state.Document.LinkReferenceDefinitions.ContainsKey(label))
{
label = null;
}
}
- text.Restore(ref saved);
+ state.Text = saved;
// Else we insert a LinkDelimiter
- text.NextChar();
+ state.Text.NextChar();
state.Inline = new LinkDelimiterInline(this)
{
Type = DelimiterType.Open,
@@ -74,10 +72,10 @@ namespace Textamina.Markdig.Syntax
return true;
case ']':
- text.NextChar();
+ state.Text.NextChar();
if (state.Inline != null)
{
- if (TryProcessLinkOrImage(state, text))
+ if (TryProcessLinkOrImage(state, ref state.Text))
{
return true;
}
@@ -146,7 +144,7 @@ namespace Textamina.Markdig.Syntax
return isValidLink;
}
- private bool TryProcessLinkOrImage(InlineParserState inlineState, StringLineGroup text)
+ private bool TryProcessLinkOrImage(InlineParserState inlineState, ref StringSlice text)
{
LinkDelimiterInline openParent = null;
foreach (var parent in inlineState.Inline.FindParentOfType())
@@ -164,7 +162,7 @@ namespace Textamina.Markdig.Syntax
case '(':
string url;
string title;
- if (LinkHelper.TryParseInlineLink(text, out url, out title))
+ if (LinkHelper.TryParseInlineLink(ref text, out url, out title))
{
// Inline Link
var link = new LinkInline()
@@ -192,7 +190,7 @@ namespace Textamina.Markdig.Syntax
// Handle Collapsed links
if (text.CurrentChar == '[')
{
- if (text.PeekCharOnSameLine() == ']')
+ if (text.PeekChar(1) == ']')
{
label = openParent.Label;
text.NextChar(); // Skip [
@@ -204,7 +202,7 @@ namespace Textamina.Markdig.Syntax
label = openParent.Label;
}
- if (label != null || LinkHelper.TryParseLabel(text, true, out label))
+ if (label != null || LinkHelper.TryParseLabel(ref text, true, out label))
{
if (ProcessLinkReference(inlineState, label, openParent.IsImage,
openParent.FirstChild))
diff --git a/src/Textamina.Markdig/Syntax/Inlines/LiteralInline.cs b/src/Textamina.Markdig/Syntax/Inlines/LiteralInline.cs
index e0e7a5d7..fbd63cb6 100644
--- a/src/Textamina.Markdig/Syntax/Inlines/LiteralInline.cs
+++ b/src/Textamina.Markdig/Syntax/Inlines/LiteralInline.cs
@@ -41,7 +41,7 @@ namespace Textamina.Markdig.Syntax
builder = literal.ContentBuilder;
}
- var text = state.Lines;
+ var text = state.Text;
builder.Append(text.CurrentChar);
text.NextChar();
return true;
diff --git a/src/Textamina.Markdig/Syntax/LeafBlock.cs b/src/Textamina.Markdig/Syntax/LeafBlock.cs
index bcea30ad..1d6cb9b7 100644
--- a/src/Textamina.Markdig/Syntax/LeafBlock.cs
+++ b/src/Textamina.Markdig/Syntax/LeafBlock.cs
@@ -6,18 +6,13 @@ namespace Textamina.Markdig.Syntax
{
protected LeafBlock(BlockParser parser) : base(parser)
{
- Lines = new StringLineGroup();
+ Lines = new StringSliceList();
}
- public StringLineGroup Lines { get; set; }
+ public StringSliceList Lines { get; set; }
public Inline Inline { get; set; }
public bool NoInline { get; set; }
-
- internal void Append(StringLine line)
- {
- Lines.Add(line);
- }
}
}
\ No newline at end of file
diff --git a/src/Textamina.Markdig/Syntax/LinkReferenceDefinitionBlock.cs b/src/Textamina.Markdig/Syntax/LinkReferenceDefinitionBlock.cs
index fa8892af..bba37aae 100644
--- a/src/Textamina.Markdig/Syntax/LinkReferenceDefinitionBlock.cs
+++ b/src/Textamina.Markdig/Syntax/LinkReferenceDefinitionBlock.cs
@@ -23,14 +23,14 @@ namespace Textamina.Markdig.Syntax
public string Title { get; set; }
- public static bool TryParse(StringLineGroup lines, out LinkReferenceDefinitionBlock block)
+ public static bool TryParse(ref StringSlice text, out LinkReferenceDefinitionBlock block)
{
block = null;
string label;
string url;
string title;
- if (!LinkHelper.TryParseLinkReferenceDefinition(lines, out label, out url, out title))
+ if (!LinkHelper.TryParseLinkReferenceDefinition(ref text, out label, out url, out title))
{
return false;
}
diff --git a/src/Textamina.Markdig/Syntax/ListBlock.cs b/src/Textamina.Markdig/Syntax/ListBlock.cs
index 554591f3..6037e20b 100644
--- a/src/Textamina.Markdig/Syntax/ListBlock.cs
+++ b/src/Textamina.Markdig/Syntax/ListBlock.cs
@@ -38,26 +38,24 @@ namespace Textamina.Markdig.Syntax
return MatchLineResult.Skip;
}
- var liner = state.Line;
-
// When both a thematic break and a list item are possible
// interpretations of a line, the thematic break takes precedence
- var save = liner.Save();
- if (BreakBlock.Parser.Match(state) == MatchLineResult.Last)
+ var save = state.Line;
+ if (ThematicBreakBlock.Parser.Match(state) == MatchLineResult.Last)
{
- // Remove the BreakBlock as we will let the BreakBlock to catch it later
+ // Remove the ThematicBreakBlock as we will let the ThematicBreakBlock to catch it later
state.NewBlocks.Pop();
return MatchLineResult.None;
}
- liner.Restore(ref save);
+ state.SetCurrentLine(ref save);
// 5.2 List items
// TODO: Check with specs, it is not clear that list marker or bullet marker must be followed by at least 1 space
int preIndent = 0;
- for (int i = liner.Start - 1; i >= 0; i--)
+ for (int i = state.Line.Start - 1; i >= 0; i--)
{
- if (liner[i].IsSpaceOrTab())
+ if (state.Line[i].IsSpaceOrTab())
{
preIndent++;
}
@@ -67,7 +65,7 @@ namespace Textamina.Markdig.Syntax
}
}
- var saveLiner = liner.Save();
+ var saveLiner = state.Line;
// If we have already a ListItemBlock, we are going to try to append to it
var listItem = state.Pending as ListItemBlock;
@@ -78,7 +76,7 @@ namespace Textamina.Markdig.Syntax
// Allow all blanks lines if the last block is a fenced code block
// Allow 1 blank line inside a list
// If > 1 blank line, terminate this list
- var isBlankLine = liner.IsBlankLine();
+ var isBlankLine = state.IsBlankLine;
//if (isBlankLine && !(state.LastBlock is FencedCodeBlock)) // TODO: Handle this case
var isInFencedBlock = state.LastBlock is FencedCodeBlock;
if (isBlankLine)
@@ -114,26 +112,26 @@ namespace Textamina.Markdig.Syntax
list.CountBlankLinesReset = 0;
- var c = liner.Current;
- var startPosition = liner.Column;
+ var c = state.Line.CurrentChar;
+ var startPosition = state.Line.Start;
// List Item starting with a blank line (-1)
if (listItem.NumberOfSpaces < 0)
{
int expectedCount = -listItem.NumberOfSpaces;
int countSpaces = 0;
- var saved = new StringLine.State();
+ var saved = new StringSlice();
while (c.IsSpaceOrTab())
{
- c = liner.NextChar();
- countSpaces = preIndent + liner.Column - startPosition;
+ c = state.Line.NextChar();
+ countSpaces = preIndent + state.Line.Column - startPosition;
if (countSpaces == expectedCount)
{
- saved = liner.Save();
+ saved = state.Line;
}
else if (countSpaces >= 4)
{
- liner.Restore(ref saved);
+ state.SetCurrentLine(ref saved);
countSpaces = expectedCount;
break;
}
@@ -149,15 +147,15 @@ namespace Textamina.Markdig.Syntax
{
while (c.IsSpaceOrTab())
{
- c = liner.NextChar();
- var countSpaces = preIndent + liner.Column - startPosition;
+ c = state.Line.NextChar();
+ var countSpaces = preIndent + state.Line.Column - startPosition;
if (countSpaces >= listItem.NumberOfSpaces)
{
return MatchLineResult.Continue;
}
}
}
- liner.Restore(ref saveLiner);
+ state.SetCurrentLine(ref saveLiner);
}
return TryParseListItem(ref state, preIndent);
@@ -165,33 +163,32 @@ namespace Textamina.Markdig.Syntax
private MatchLineResult TryParseListItem(ref BlockParserState state, int preIndent)
{
- var liner = state.Line;
-
var isInList = state.Pending is ListItemBlock;
- var preStartPosition = liner.Start;
+ var preStartPosition = state.Line.Start;
- var c = liner.Current;
+ var c = state.Line.CurrentChar;
if (isInList)
{
while (c.IsSpaceOrTab())
{
- c = liner.NextChar();
+ c = state.Line.NextChar();
}
}
else
{
- liner.SkipLeadingSpaces3();
- c = liner.Current;
+ // TODO
+ //state.Line.SkipLeadingSpaces3();
+ c = state.Line.CurrentChar;
}
- preIndent = preIndent + liner.Start - preStartPosition;
+ preIndent = preIndent + state.Line.Start - preStartPosition;
var isOrdered = false;
var bulletChar = (char) 0;
int orderedStart = 0;
var orderedDelimiter = (char) 0;
- var column = liner.Start;
+ var column = state.Line.Start;
if (c.IsBulletListMarker())
{
@@ -204,7 +201,7 @@ namespace Textamina.Markdig.Syntax
while (c.IsDigit())
{
orderedStart = orderedStart*10 + c - '0';
- c = liner.NextChar();
+ c = state.Line.NextChar();
preIndent++;
countDigit++;
}
@@ -230,11 +227,11 @@ namespace Textamina.Markdig.Syntax
}
// Skip Bullet or '.'
- liner.NextChar();
+ state.Line.NextChar();
// Item starting with a blank line
int numberOfSpaces;
- if (liner.IsBlankLine())
+ if (state.IsBlankLine)
{
// Use a negative number to store the number of expected chars
numberOfSpaces = -(preIndent + 1);
@@ -243,34 +240,34 @@ namespace Textamina.Markdig.Syntax
{
var startPosition = -1;
int countSpaceAfterBullet = 0;
- var saved = new StringLine.State();
+ var saved = new StringSlice();
for (int i = 0; i <= 4; i++)
{
- c = liner.Current;
+ c = state.Line.CurrentChar;
if (!c.IsSpaceOrTab())
{
break;
}
if (i == 0)
{
- startPosition = liner.Column;
+ startPosition = state.Line.Column;
}
- var endPosition = liner.Column;
+ var endPosition = state.Line.Column;
countSpaceAfterBullet = endPosition - startPosition;
if (countSpaceAfterBullet == 1)
{
- saved = liner.Save();
+ saved = state.Line;
}
else if (countSpaceAfterBullet >= 4)
{
- liner.SpaceHeaderCount = countSpaceAfterBullet - 4;
+ //state.Line.SpaceHeaderCount = countSpaceAfterBullet - 4;
countSpaceAfterBullet = 0;
- liner.Restore(ref saved);
+ state.SetCurrentLine(ref saved);
break;
}
- liner.NextChar();
+ state.Line.NextChar();
}
// If we haven't matched any spaces, early exit
diff --git a/src/Textamina.Markdig/Syntax/ParagraphBlock.cs b/src/Textamina.Markdig/Syntax/ParagraphBlock.cs
index 0cc50af8..fdc57cd9 100644
--- a/src/Textamina.Markdig/Syntax/ParagraphBlock.cs
+++ b/src/Textamina.Markdig/Syntax/ParagraphBlock.cs
@@ -25,13 +25,15 @@ namespace Textamina.Markdig.Syntax
{
public override MatchLineResult Match(BlockParserState state)
{
- var liner = state.Line;
- liner.SkipLeadingSpaces3();
+ if (state.IsCodeIndent)
+ {
+ return MatchLineResult.None;
+ }
- var column = liner.Start;
+ var column = state.Column;
// Else it is a continue, we don't break on blank lines
- var isBlankLine = liner.IsBlankLine();
+ var isBlankLine = state.IsBlankLine;
var paragraph = state.Pending as ParagraphBlock;
@@ -59,9 +61,9 @@ namespace Textamina.Markdig.Syntax
{
var headingChar = (char) 0;
bool checkForSpaces = false;
- for (int i = liner.Start; i <= liner.End; i++)
+ for (int i = state.Start; i <= state.EndOffset; i++)
{
- var c = liner[i];
+ var c = state.Line[i];
if (headingChar == 0)
{
if (c == '=' || c == '-')
@@ -112,10 +114,7 @@ namespace Textamina.Markdig.Syntax
Level = level,
Lines = paragraph.Lines,
};
- foreach (var line in heading.Lines)
- {
- line.Trim();
- }
+ heading.Lines.Trim();
// Remove the paragraph as a pending block
state.NewBlocks.Push(heading);
@@ -129,46 +128,46 @@ namespace Textamina.Markdig.Syntax
return result;
}
- private bool TryMatchLinkReferenceDefinition(StringLineGroup localLineGroup, BlockParserState state)
+ private bool TryMatchLinkReferenceDefinition(StringSliceList localLineGroup, BlockParserState state)
{
bool atLeastOneFound = false;
- var saved = new StringLineGroup.State();
- while (true)
- {
- // If we have found a LinkReferenceDefinition, we can discard the previous paragraph
- localLineGroup.Save(ref saved);
- LinkReferenceDefinitionBlock linkReferenceDefinition;
- if (LinkReferenceDefinitionBlock.TryParse(localLineGroup, out linkReferenceDefinition))
- {
- if (!state.Root.LinkReferenceDefinitions.ContainsKey(linkReferenceDefinition.Label))
- {
- state.Root.LinkReferenceDefinitions[linkReferenceDefinition.Label] = linkReferenceDefinition;
- }
- atLeastOneFound = true;
+ //var saved = new StringSliceList.State();
+ //while (true)
+ //{
+ // // If we have found a LinkReferenceDefinition, we can discard the previous paragraph
+ // localLineGroup.Save(ref saved);
+ // LinkReferenceDefinitionBlock linkReferenceDefinition;
+ // if (LinkReferenceDefinitionBlock.TryParse(localLineGroup, out linkReferenceDefinition))
+ // {
+ // if (!state.Root.LinkReferenceDefinitions.ContainsKey(linkReferenceDefinition.Label))
+ // {
+ // state.Root.LinkReferenceDefinitions[linkReferenceDefinition.Label] = linkReferenceDefinition;
+ // }
+ // atLeastOneFound = true;
- // Remove lines that have been matched
- if (localLineGroup.LinePosition == localLineGroup.Count)
- {
- localLineGroup.Clear();
- }
- else
- {
- for (int i = localLineGroup.LinePosition - 1; i >= 0; i--)
- {
- localLineGroup.RemoveAt(i);
- }
- }
- }
- else
- {
- if (!atLeastOneFound)
- {
- localLineGroup.Restore(ref saved);
- }
- break;
- }
- }
+ // // Remove lines that have been matched
+ // if (localLineGroup.LinePosition == localLineGroup.Count)
+ // {
+ // localLineGroup.Clear();
+ // }
+ // else
+ // {
+ // for (int i = localLineGroup.LinePosition - 1; i >= 0; i--)
+ // {
+ // localLineGroup.RemoveAt(i);
+ // }
+ // }
+ // }
+ // else
+ // {
+ // if (!atLeastOneFound)
+ // {
+ // localLineGroup.Restore(ref saved);
+ // }
+ // break;
+ // }
+ //}
return atLeastOneFound;
}
@@ -193,7 +192,7 @@ namespace Textamina.Markdig.Syntax
var lineCount = lines.Count;
for (int i = 0; i < lineCount; i++)
{
- var line = lines[i];
+ var line = lines.Slices[i];
line.Trim();
}
}
diff --git a/src/Textamina.Markdig/Syntax/QuoteBlock.cs b/src/Textamina.Markdig/Syntax/QuoteBlock.cs
index 0f5262f9..57ecd06f 100644
--- a/src/Textamina.Markdig/Syntax/QuoteBlock.cs
+++ b/src/Textamina.Markdig/Syntax/QuoteBlock.cs
@@ -15,17 +15,18 @@ namespace Textamina.Markdig.Syntax
{
public override MatchLineResult Match(BlockParserState state)
{
- var liner = state.Line;
-
- liner.SkipLeadingSpaces3();
+ if (state.IsCodeIndent)
+ {
+ return MatchLineResult.None;
+ }
// 5.1 Block quotes
// A block quote marker consists of 0-3 spaces of initial indent, plus (a) the character > together with a following space, or (b) a single character > not followed by a space.
- var c = liner.Current;
- var column = liner.Start;
+ var c = state.CurrentChar;
+ var column = state.Column;
if (c != '>')
{
- if (state.Pending != null && liner.IsBlankLine())
+ if (state.Pending != null && state.IsBlankLine)
{
state.Close(state.Pending);
return MatchLineResult.None;
@@ -33,10 +34,10 @@ namespace Textamina.Markdig.Syntax
return MatchLineResult.None;
}
- c = liner.NextChar();
+ c = state.NextChar();
if (c.IsSpace())
{
- liner.NextChar();
+ state.NextChar();
}
if (state.Pending == null)
diff --git a/src/Textamina.Markdig/Syntax/StringLine.cs b/src/Textamina.Markdig/Syntax/StringLine.cs
deleted file mode 100644
index c8c7a08d..00000000
--- a/src/Textamina.Markdig/Syntax/StringLine.cs
+++ /dev/null
@@ -1,251 +0,0 @@
-using System;
-using System.Runtime.CompilerServices;
-using Textamina.Markdig.Helpers;
-using Textamina.Markdig.Parsing;
-
-namespace Textamina.Markdig.Syntax
-{
- public sealed class StringLine
- {
- public StringLine(string text, int lineIndex = 0)
- {
- if (text == null) throw new ArgumentNullException(nameof(text));
- LineIndex = lineIndex;
- Text = text;
- Start = 0;
- End = Text.Length - 1;
- Column = 0;
- SpaceHeaderCount = 0;
- Current = End >= 0 ? Text[0] : (char)0;
- }
-
- public int LineIndex { get; }
-
- public string Text { get; private set; }
-
- public int Start { get; set; }
-
- public int End { get; set; }
-
- public int SpaceHeaderCount { get; set; }
-
- public int Column { get; private set; }
-
- public char Current { get; private set; }
-
- public bool IsEol => Start > End;
-
- private bool isBlankLine;
-
- public char this[int index] => Text[index];
-
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
- public State Save()
- {
- return new State(Start, End, Column, SpaceHeaderCount, Current);
- }
-
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
- public void Restore(State state)
- {
- Restore(ref state);
- }
-
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
- public void Restore(ref State state)
- {
- Start = state.Start;
- End = state.End;
- Column = state.Column;
- SpaceHeaderCount = state.SpaceHeaderCount;
- Current = state.Current;
- }
-
- public char NextChar()
- {
- Start++;
- if (Start <= End)
- {
- // If previous character was a tab make the Column += 4
- Column++;
- if (Current.IsTab())
- {
- // Align the tab on a column
- Column = ((Column + 3) / 4) * 4;
- }
- Current = Text[Start].EscapeInsecure();
- }
- else
- {
- Start = End + 1;
- Current = (char) 0;
- }
- return Current;
- }
-
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
- public char PeekChar(int offset)
- {
- var index = Start + offset;
- return index <= End ? Text[index].EscapeInsecure() : (char) 0;
- }
-
- public bool Match(string text, int offset = 0)
- {
- return Match(text, End, offset);
- }
-
- public bool Match(string text, int end, int offset)
- {
- var index = Start + offset;
- int i = 0;
- for (; index <= end && i < text.Length; i++, index++)
- {
- if (text[i] != Text[index])
- {
- return false;
- }
- }
-
- return i == text.Length;
- }
-
- public bool MatchLowercase(string text, int end, int offset)
- {
- var index = Start + offset;
- int i = 0;
- for (; index <= end && i < text.Length; i++, index++)
- {
- if (text[i] != char.ToLowerInvariant(Text[index]))
- {
- return false;
- }
- }
-
- return i == text.Length;
- }
-
- public bool Search(string text, int offset = 0)
- {
- var end = End - text.Length + 1;
- for (int i = Start; i <= end; i++)
- {
- if (Match(text, End, i))
- {
- return true;
- }
- }
- return false;
- }
-
- public bool SearchLowercase(string text, int offset = 0)
- {
- var end = End - text.Length + 1;
- for (int i = Start; i <= end; i++)
- {
- if (MatchLowercase(text, End, i))
- {
- return true;
- }
- }
- return false;
- }
-
- public bool IsBlankLine()
- {
- if (isBlankLine)
- {
- return true;
- }
-
- for (int i = Start; i <= End; i++)
- {
- if (!Text[i].IsSpace())
- {
- return false;
- }
- }
- isBlankLine = true;
- return true;
- }
-
- [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
- public void SkipLeadingSpaces3()
- {
- var c = Current;
- if (c.IsSpace())
- {
- c = NextChar();
- if (c.IsSpace())
- {
- c = NextChar();
- if (c.IsSpace())
- {
- NextChar();
- }
- }
- }
- }
-
- public StringSlice ToSlice()
- {
- return new StringSlice(Text, Start, End);
- }
-
- public void TrimStart(bool includeTabs = false)
- {
- // Strip leading spaces
- var c = Current;
- while (includeTabs ? c.IsSpaceOrTab() :c.IsSpace())
- {
- c = NextChar();
- }
- }
-
- public void TrimEnd(bool includeTabs = false)
- {
- for (int i = End; i >= Start; i--)
- {
- End = i;
- var c = this[i];
- if (!(includeTabs ? c.IsSpaceOrTab() : c.IsSpace()))
- {
- break;
- }
- }
- }
-
- public void Trim()
- {
- TrimStart();
- TrimEnd();
- }
-
- public override string ToString()
- {
- return Start <= End ? Text.Substring(Start, End - Start + 1) : string.Empty;
- }
-
- public struct State
- {
- public State(int start, int end, int column, int spaceHeaderCount, char current)
- {
- Start = start;
- End = end;
- Column = column;
- SpaceHeaderCount = spaceHeaderCount;
- Current = current;
- }
-
- public readonly int Start;
-
- public readonly int End;
-
- public readonly int Column;
-
- public readonly int SpaceHeaderCount;
-
- public readonly char Current;
- }
- }
-}
\ No newline at end of file
diff --git a/src/Textamina.Markdig/Syntax/StringLineGroup.cs b/src/Textamina.Markdig/Syntax/StringLineGroup.cs
deleted file mode 100644
index 0d766987..00000000
--- a/src/Textamina.Markdig/Syntax/StringLineGroup.cs
+++ /dev/null
@@ -1,265 +0,0 @@
-using System;
-using System.Collections.ObjectModel;
-using System.Text;
-using Textamina.Markdig.Helpers;
-using Textamina.Markdig.Parsing;
-
-namespace Textamina.Markdig.Syntax
-{
- public class StringLineGroup : Collection
- {
- private StringLine currentLine;
-
- public StringLineGroup()
- {
- }
-
- public StringLineGroup(string text)
- {
- if (text == null) throw new ArgumentNullException(nameof(text));
- Add(new StringLine(text));
- }
-
- public int LinePosition { get; private set; }
-
- public int ColumnPosition { get; private set; }
-
- public StringLine Current => currentLine;
-
- public char CurrentChar { get; private set; }
-
- public char PreviousChar1 { get; private set; }
-
- public char PreviousChar2 { get; private set; }
-
- public void Reset()
- {
- ColumnPosition = -1;
- LinePosition = 0;
- currentLine = Count > 0 ? this[0] : null;
- if (currentLine != null)
- {
- ColumnPosition = currentLine.Start - 1;
- }
- NextChar();
- }
-
- public void SetColumn(int index)
- {
- if (Current != null && index <= Current.End)
- {
- CurrentChar = Current[index];
- ColumnPosition = index;
- // Don't set previous char
- PreviousChar1 = '\0';
- PreviousChar2 = '\0';
- }
- }
-
- public char PeekCharOnSameLine()
- {
- if (Current != null && (ColumnPosition+1) <= Current.End)
- {
- return Current[ColumnPosition + 1];
- }
- return (char)0;
- }
-
- protected override void ClearItems()
- {
- base.ClearItems();
- Reset();
- }
-
- protected override void InsertItem(int index, StringLine item)
- {
- base.InsertItem(index, item);
- if (index == 0)
- {
- Reset();
- }
- }
-
- protected override void SetItem(int index, StringLine item)
- {
- base.SetItem(index, item);
- if (index == 0)
- {
- Reset();
- }
- }
-
- protected override void RemoveItem(int index)
- {
- base.RemoveItem(index);
- if (index == 0)
- {
- Reset();
- }
- }
-
- public bool IsEndOfLines => CurrentChar == '\0';
-
- public State Save()
- {
- return new State(currentLine, LinePosition, ColumnPosition, CurrentChar, PreviousChar1, PreviousChar2);
- }
-
- public void Save(ref State state)
- {
- state.CurrentLine = currentLine;
- state.LinePosition = LinePosition;
- state.ColumnPosition = ColumnPosition;
- state.Current = CurrentChar;
- state.PreviousChar1 = PreviousChar1;
- state.PreviousChar2 = PreviousChar2;
- }
-
- public void Restore(ref State state)
- {
- currentLine = state.CurrentLine;
- LinePosition = state.LinePosition;
- ColumnPosition = state.ColumnPosition;
- CurrentChar = state.Current;
- PreviousChar1 = state.PreviousChar1;
- PreviousChar2 = state.PreviousChar2;
- }
-
- public char NextChar()
- {
- PreviousChar2 = PreviousChar1;
- PreviousChar1 = CurrentChar;
- if (currentLine != null)
- {
- ColumnPosition++;
- if (ColumnPosition <= currentLine.End)
- {
- CurrentChar = currentLine[ColumnPosition].EscapeInsecure();
- }
- else
- {
- LinePosition++;
- if (LinePosition < Count)
- {
- currentLine = this[LinePosition];
- }
- else
- {
- currentLine = null;
- LinePosition = Count;
- }
-
- ColumnPosition = -1;
- if (currentLine != null)
- {
- ColumnPosition = currentLine.Start - 1;
- }
- CurrentChar = currentLine != null ? '\n' : '\0';
- }
- }
- else
- {
- CurrentChar = '\0';
- }
-
- return CurrentChar;
- }
-
- public bool SkipWhiteSpaces()
- {
- bool hasWhitespaces = false;
- while (CurrentChar.IsWhitespace())
- {
- NextChar();
- hasWhitespaces = true;
- }
- return hasWhitespaces;
- }
-
- public bool SkipWhiteSpaces(out int newLineCount)
- {
- bool hasWhitespaces = false;
- newLineCount = 0;
- while (CurrentChar.IsWhitespace())
- {
- if (CurrentChar == '\n')
- {
- newLineCount++;
- }
- NextChar();
- hasWhitespaces = true;
- }
- return hasWhitespaces;
- }
-
- public void TrimStart()
- {
- if (Count == 0)
- {
- return;
- }
-
- // Strip leading and
- this[0].TrimStart();
- Reset();
- }
-
- public void TrimEnd()
- {
- if (Count == 0)
- {
- return;
- }
-
- this[Count - 1].TrimEnd();
- Reset();
- }
-
- public void Trim()
- {
- TrimStart();
- TrimEnd();
- }
-
- public override string ToString()
- {
- var stringBuilder = new StringBuilder();
- bool firstLine = true;
- foreach (var line in this)
- {
- if (!firstLine)
- {
- stringBuilder.Append('\n');
- }
- stringBuilder.Append(line);
- firstLine = false;
- }
- return stringBuilder.ToString();
- }
-
- public struct State
- {
- public State(StringLine currentLine, int linePosition, int columnPosition, char current, char previousChar1, char previousChar2)
- {
- CurrentLine = currentLine;
- LinePosition = linePosition;
- ColumnPosition = columnPosition;
- Current = current;
- PreviousChar1 = previousChar1;
- PreviousChar2 = previousChar2;
- }
-
- public StringLine CurrentLine;
-
- public int LinePosition;
-
- public int ColumnPosition;
-
- public char Current;
-
- public char PreviousChar1;
-
- public char PreviousChar2;
- }
- }
-}
\ No newline at end of file
diff --git a/src/Textamina.Markdig/Syntax/StringSlice.cs b/src/Textamina.Markdig/Syntax/StringSlice.cs
index a9d48a67..5658d86a 100644
--- a/src/Textamina.Markdig/Syntax/StringSlice.cs
+++ b/src/Textamina.Markdig/Syntax/StringSlice.cs
@@ -1,25 +1,171 @@
-namespace Textamina.Markdig.Syntax
+using System;
+using System.Runtime.CompilerServices;
+using Textamina.Markdig.Helpers;
+
+namespace Textamina.Markdig.Syntax
{
public struct StringSlice
{
- public StringSlice(string text, int start, int end)
+ public StringSlice(string text)
{
+ if (text == null) throw new ArgumentNullException(nameof(text));
Text = text;
- Start = start;
- End = end;
+ Start = 0;
+ End = Text.Length - 1;
}
- public string Text;
+ public readonly string Text;
public int Start;
public int End;
- public int Length
- {
- get { return End - Start; }
+ public int Column => Start;
- set { End = Start + value; }
+ public char CurrentChar => Start <= End ? this[Start] : '\0';
+
+ public bool IsEndOfSlice => Start > End;
+
+ public char this[int index] => Text[index].EscapeInsecure();
+
+ [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ public char NextChar()
+ {
+ Start++;
+ if (Start > End)
+ {
+ Start = End + 1;
+ }
+ return CurrentChar;
+ }
+
+ [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ public char PeekChar(int offset)
+ {
+ var index = Start + offset;
+ return index >= Start && index <= End ? Text[index].EscapeInsecure() : (char) 0;
+ }
+
+ [MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
+ public char PeekCharExtra(int offset)
+ {
+ var index = Start + offset;
+ return index >= 0 && index < Text.Length ? Text[index].EscapeInsecure() : (char)0;
+ }
+
+ public bool Match(string text, int offset = 0)
+ {
+ return Match(text, End, offset);
+ }
+
+ public bool Match(string text, int end, int offset)
+ {
+ var index = Start + offset;
+ int i = 0;
+ for (; index <= end && i < text.Length; i++, index++)
+ {
+ if (text[i] != Text[index])
+ {
+ return false;
+ }
+ }
+
+ return i == text.Length;
+ }
+
+ public bool MatchLowercase(string text, int end, int offset)
+ {
+ var index = Start + offset;
+ int i = 0;
+ for (; index <= end && i < text.Length; i++, index++)
+ {
+ if (text[i] != char.ToLowerInvariant(Text[index]))
+ {
+ return false;
+ }
+ }
+
+ return i == text.Length;
+ }
+
+ public bool Search(string text, int offset = 0)
+ {
+ var end = End - text.Length + 1;
+ for (int i = Start; i <= end; i++)
+ {
+ if (Match(text, End, i))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public bool SearchLowercase(string text, int offset = 0)
+ {
+ var end = End - text.Length + 1;
+ for (int i = Start; i <= end; i++)
+ {
+ if (MatchLowercase(text, End, i))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public bool TrimStart()
+ {
+ // Strip leading spaces
+ var c = CurrentChar;
+ var hasWhitespaces = false;
+ while (c.IsWhitespace())
+ {
+ c = NextChar();
+ hasWhitespaces = true;
+ }
+ return hasWhitespaces;
+ }
+
+ public bool TrimStart(out int newLineCount)
+ {
+ bool hasWhitespaces = false;
+ newLineCount = 0;
+ var c = CurrentChar;
+ while (c.IsWhitespace())
+ {
+ if (c == '\n')
+ {
+ newLineCount++;
+ }
+ c = NextChar();
+ hasWhitespaces = true;
+ }
+ return hasWhitespaces;
+ }
+
+ public void TrimEnd(bool includeTabs = false)
+ {
+ for (int i = End; i >= Start; i--)
+ {
+ End = i;
+ var c = this[i];
+ if (!(includeTabs ? c.IsSpaceOrTab() : c.IsSpace()))
+ {
+ break;
+ }
+ }
+ }
+
+ public void Trim()
+ {
+ TrimStart();
+ TrimEnd();
+ }
+
+ public override string ToString()
+ {
+ return Start <= End ? Text.Substring(Start, End - Start + 1) : string.Empty;
}
}
}
\ No newline at end of file
diff --git a/src/Textamina.Markdig/Syntax/StringSliceList.cs b/src/Textamina.Markdig/Syntax/StringSliceList.cs
new file mode 100644
index 00000000..3a1b54b3
--- /dev/null
+++ b/src/Textamina.Markdig/Syntax/StringSliceList.cs
@@ -0,0 +1,67 @@
+using System;
+using System.Text;
+using Textamina.Markdig.Helpers;
+
+namespace Textamina.Markdig.Syntax
+{
+ public class StringSliceList
+ {
+ private static readonly StringSlice[] Empty = new StringSlice[0];
+
+ private StringSlice currentLine;
+
+ public StringSliceList()
+ {
+ Slices = Empty;
+ }
+
+ public StringSliceList(string text)
+ {
+ if (text == null) throw new ArgumentNullException(nameof(text));
+ Append(new StringSlice(text));
+ }
+
+ public StringSlice[] Slices;
+
+ public int Count;
+
+ public void Append(ref StringSlice slice)
+ {
+ if (Count == Slices.Length) IncreaseCapacity();
+ Slices[Count++] = slice;
+ }
+
+ public void Append(StringSlice slice)
+ {
+ if (Count == Slices.Length) IncreaseCapacity();
+ Slices[Count++] = slice;
+ }
+
+ private void IncreaseCapacity()
+ {
+ int newCapacity = Slices.Length == 0 ? 4 : Slices.Length * 2;
+ var newItems = new StringSlice[newCapacity];
+ if (Count > 0)
+ {
+ Array.Copy(Slices, 0, newItems, 0, Count);
+ }
+ Slices = newItems;
+ }
+
+ public override string ToString()
+ {
+ var stringBuilder = StringBuilderCache.Local();
+ for(int i = 0; i < Count; i++)
+ {
+ if (i > 0)
+ {
+ stringBuilder.Append('\n');
+ }
+ stringBuilder.Append(Slices[i]);
+ }
+ var str = stringBuilder.ToString();
+ stringBuilder.Clear();
+ return str;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Textamina.Markdig/Syntax/StringSliceListExtensions.cs b/src/Textamina.Markdig/Syntax/StringSliceListExtensions.cs
new file mode 100644
index 00000000..a59a695e
--- /dev/null
+++ b/src/Textamina.Markdig/Syntax/StringSliceListExtensions.cs
@@ -0,0 +1,14 @@
+namespace Textamina.Markdig.Syntax
+{
+ public static class StringSliceListExtensions
+ {
+ public static void Trim(this StringSliceList slices)
+ {
+ for (int i = 0; i < slices.Count; i++)
+ {
+ slices.Slices[i].Trim();
+ }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/Textamina.Markdig/Syntax/BreakBlock.cs b/src/Textamina.Markdig/Syntax/ThematicBreakBlock.cs
similarity index 80%
rename from src/Textamina.Markdig/Syntax/BreakBlock.cs
rename to src/Textamina.Markdig/Syntax/ThematicBreakBlock.cs
index 8371f068..4ca96645 100644
--- a/src/Textamina.Markdig/Syntax/BreakBlock.cs
+++ b/src/Textamina.Markdig/Syntax/ThematicBreakBlock.cs
@@ -6,11 +6,11 @@ namespace Textamina.Markdig.Syntax
///
/// Repressents a thematic break.
///
- public class BreakBlock : LeafBlock
+ public class ThematicBreakBlock : LeafBlock
{
public new static readonly BlockParser Parser = new ParserInternal();
- public BreakBlock(BlockParser parser) : base(parser)
+ public ThematicBreakBlock(BlockParser parser) : base(parser)
{
NoInline = true;
}
@@ -19,20 +19,23 @@ namespace Textamina.Markdig.Syntax
{
public override MatchLineResult Match(BlockParserState state)
{
- var liner = state.Line;
- liner.SkipLeadingSpaces3();
+ if (state.IsCodeIndent)
+ {
+ return MatchLineResult.None;
+ }
- var column = liner.Start;
+ var column = state.Column;
// 4.1 Thematic breaks
// A line consisting of 0-3 spaces of indentation, followed by a sequence of three or more matching -, _, or * characters, each followed optionally by any number of spaces
- var c = liner.Current;
+ var c = state.CurrentChar;
int count = 0;
var matchChar = (char)0;
bool hasSpacesSinceLastMatch = false;
bool hasInnerSpaces = false;
- while (!liner.IsEol)
+ int offset = 0;
+ while (c != '\0')
{
if (count == 0 && (c == '-' || c == '_' || c == '*'))
{
@@ -56,7 +59,9 @@ namespace Textamina.Markdig.Syntax
{
hasSpacesSinceLastMatch = true;
}
- c = liner.NextChar();
+
+ offset++;
+ c = state.PeekChar(offset);
}
// If it as less than 3 chars or it is a setex heading and we are already in a paragraph, let the paragraph handle it
@@ -77,8 +82,8 @@ namespace Textamina.Markdig.Syntax
return MatchLineResult.None;
}
- state.NewBlocks.Push(new BreakBlock(this) { Column = column });
- return MatchLineResult.Last;
+ state.NewBlocks.Push(new ThematicBreakBlock(this) { Column = column });
+ return MatchLineResult.LastDiscard;
}
}
}
diff --git a/src/Textamina.Markdig/Textamina.Markdig.csproj b/src/Textamina.Markdig/Textamina.Markdig.csproj
index 8d305c87..42455093 100644
--- a/src/Textamina.Markdig/Textamina.Markdig.csproj
+++ b/src/Textamina.Markdig/Textamina.Markdig.csproj
@@ -63,7 +63,6 @@
-
@@ -75,7 +74,8 @@
-
+
+
@@ -86,8 +86,8 @@
-
-
+
+