mirror of
https://github.com/xoofx/markdig.git
synced 2026-10-08 14:48:32 +00:00
134 lines
4.8 KiB
C#
134 lines
4.8 KiB
C#
|
|
|
|
|
|
using Textamina.Markdig.Helpers;
|
|
using Textamina.Markdig.Parsing;
|
|
|
|
namespace Textamina.Markdig.Syntax
|
|
{
|
|
public class ListBlock : ContainerBlock
|
|
{
|
|
public static readonly BlockParser Parser = new ParserInternal();
|
|
|
|
public char BulletChar { get; set; }
|
|
|
|
private int consecutiveBlankLines;
|
|
|
|
private class ParserInternal : BlockParser
|
|
{
|
|
public override MatchLineResult Match(MatchLineState state)
|
|
{
|
|
var liner = state.Line;
|
|
|
|
// 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
|
|
|
|
var saveLiner = liner.Save();
|
|
|
|
// If we have already a ListItemBlock, we are going to try to append to it
|
|
if (state.Block != null)
|
|
{
|
|
var listItem = (ListItemBlock) state.Block;
|
|
var list = (ListBlock) listItem.Parent;
|
|
|
|
// 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();
|
|
if (isBlankLine && !(state.LastBlock is FencedCodeBlock))
|
|
{
|
|
list.consecutiveBlankLines++;
|
|
if (list.consecutiveBlankLines > 1)
|
|
{
|
|
return MatchLineResult.LastDiscard;
|
|
}
|
|
|
|
return MatchLineResult.Continue;
|
|
}
|
|
|
|
list.consecutiveBlankLines = 0;
|
|
|
|
var c = liner.Current;
|
|
var startPosition = liner.Column;
|
|
while (CharHelper.IsSpaceOrTab(c))
|
|
{
|
|
c = liner.NextChar();
|
|
var endPosition = liner.Column;
|
|
if ((endPosition - startPosition) >= listItem.NumberOfSpaces)
|
|
{
|
|
return MatchLineResult.Continue;
|
|
}
|
|
}
|
|
liner.Restore(ref saveLiner);
|
|
}
|
|
|
|
return TryParseListItem(ref state);
|
|
}
|
|
|
|
private MatchLineResult TryParseListItem(ref MatchLineState state)
|
|
{
|
|
var liner = state.Line;
|
|
|
|
var preStartPosition = liner.Start;
|
|
liner.SkipLeadingSpaces3();
|
|
var preIndent = liner.Start - preStartPosition;
|
|
var c = liner.Current;
|
|
if (CharHelper.IsBulletListMarker(c))
|
|
{
|
|
var listType = c;
|
|
|
|
var startPosition = -1;
|
|
var endPosition = -1;
|
|
var tabToSpacesCount = 0;
|
|
int deltaPositions = 0;
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
c = liner.NextChar();
|
|
if (!CharHelper.IsSpaceOrTab(c))
|
|
{
|
|
break;
|
|
}
|
|
if (i == 0)
|
|
{
|
|
startPosition = liner.Column;
|
|
}
|
|
endPosition = liner.Column;
|
|
|
|
deltaPositions = endPosition - startPosition;
|
|
if (deltaPositions >= 4)
|
|
{
|
|
liner.SpaceHeaderCount = deltaPositions - 4;
|
|
deltaPositions = 4;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If we haven't matched any spaces, early exit
|
|
if (startPosition < 0)
|
|
{
|
|
return MatchLineResult.None;
|
|
}
|
|
|
|
// Number of spaces required for the following content to be part of this list item
|
|
var numberOfSpaces = deltaPositions + 1 + preIndent;
|
|
|
|
var listItem = new ListItemBlock() {NumberOfSpaces = numberOfSpaces};
|
|
var parentList = (state.Block as ListItemBlock)?.Parent as ListBlock;
|
|
|
|
// Reset the list if it is a new list or a new type of bullet
|
|
if (parentList == null || parentList.BulletChar != listType)
|
|
{
|
|
parentList = new ListBlock() { BulletChar = listType };
|
|
}
|
|
parentList.Children.Add(listItem);
|
|
listItem.Parent = parentList;
|
|
|
|
state.Block = listItem;
|
|
|
|
return MatchLineResult.Continue;
|
|
}
|
|
return MatchLineResult.None;
|
|
}
|
|
}
|
|
}
|
|
} |