2016-02-10 00:54:08 +09:00
|
|
|
|
|
|
|
|
|
2016-02-10 20:30:38 +09:00
|
|
|
|
|
|
|
|
using Textamina.Markdig.Parsing;
|
|
|
|
|
|
|
|
|
|
namespace Textamina.Markdig.Syntax
|
2016-02-10 00:54:08 +09:00
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Repressents a fenced code block.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <remarks>
|
|
|
|
|
/// Related to CommonMark spec: 4.5 Fenced code blocks
|
|
|
|
|
/// </remarks>
|
2016-02-15 07:28:15 +09:00
|
|
|
public class FencedCodeBlock : CodeBlock
|
2016-02-10 00:54:08 +09:00
|
|
|
{
|
2016-02-15 07:28:15 +09:00
|
|
|
public new static readonly BlockParser Parser = new ParserInternal();
|
2016-02-10 00:54:08 +09:00
|
|
|
|
2016-02-15 00:34:21 +09:00
|
|
|
private int fencedCharCount;
|
2016-02-10 00:54:08 +09:00
|
|
|
|
2016-02-15 00:34:21 +09:00
|
|
|
private char fencedChar;
|
|
|
|
|
|
2016-02-15 06:58:16 +09:00
|
|
|
private bool hasFencedEnd;
|
|
|
|
|
|
|
|
|
|
private class ParserInternal : BlockParser
|
2016-02-10 00:54:08 +09:00
|
|
|
{
|
2016-02-15 07:28:15 +09:00
|
|
|
public override MatchLineResult Match(ref MatchLineState state)
|
2016-02-10 00:54:08 +09:00
|
|
|
{
|
2016-02-15 07:28:15 +09:00
|
|
|
var liner = state.Liner;
|
2016-02-10 20:30:38 +09:00
|
|
|
liner.SkipLeadingSpaces3();
|
|
|
|
|
|
2016-02-15 07:28:15 +09:00
|
|
|
var fenced = state.Block as FencedCodeBlock;
|
2016-02-15 00:34:21 +09:00
|
|
|
if (fenced != null)
|
2016-02-10 00:54:08 +09:00
|
|
|
{
|
|
|
|
|
var c = liner.Current;
|
|
|
|
|
|
2016-02-15 00:34:21 +09:00
|
|
|
int count = fenced.fencedCharCount;
|
|
|
|
|
var matchChar = fenced.fencedChar;
|
2016-02-10 00:54:08 +09:00
|
|
|
while (!liner.IsEol)
|
|
|
|
|
{
|
|
|
|
|
if (c != matchChar || count < 0)
|
|
|
|
|
{
|
|
|
|
|
if (count > 0)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-15 06:58:16 +09:00
|
|
|
fenced.hasFencedEnd = true;
|
|
|
|
|
return MatchLineResult.Last;
|
2016-02-10 00:54:08 +09:00
|
|
|
}
|
|
|
|
|
c = liner.NextChar();
|
|
|
|
|
count--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: It is unclear how to handle this correctly
|
2016-02-15 00:34:21 +09:00
|
|
|
// Break only if Eof
|
2016-02-15 06:58:16 +09:00
|
|
|
return MatchLineResult.Continue;
|
2016-02-10 00:54:08 +09:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
var c = liner.Current;
|
|
|
|
|
|
|
|
|
|
int count = 0;
|
|
|
|
|
var matchChar = (char)0;
|
|
|
|
|
while (!liner.IsEol)
|
|
|
|
|
{
|
2016-02-15 00:34:21 +09:00
|
|
|
if (count == 0 && (c == '`' || c == '~'))
|
2016-02-10 00:54:08 +09:00
|
|
|
{
|
|
|
|
|
matchChar = c;
|
|
|
|
|
}
|
|
|
|
|
else if (c != matchChar)
|
|
|
|
|
{
|
|
|
|
|
if (count < 3)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Store the number of matched string into the context
|
2016-02-15 07:28:15 +09:00
|
|
|
state.Block = new FencedCodeBlock()
|
2016-02-15 00:34:21 +09:00
|
|
|
{
|
|
|
|
|
fencedChar = matchChar,
|
|
|
|
|
fencedCharCount = count
|
|
|
|
|
};
|
2016-02-15 06:58:16 +09:00
|
|
|
return MatchLineResult.Continue;
|
2016-02-10 00:54:08 +09:00
|
|
|
}
|
|
|
|
|
c = liner.NextChar();
|
|
|
|
|
count++;
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-15 06:58:16 +09:00
|
|
|
return MatchLineResult.None;
|
2016-02-10 00:54:08 +09:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|