Files
markdig/src/Textamina.Markdig/Syntax/StringLine.cs

241 lines
5.9 KiB
C#
Raw Normal View History

2016-02-10 20:30:38 +09:00
using System;
using System.Runtime.CompilerServices;
using Textamina.Markdig.Helpers;
using Textamina.Markdig.Parsing;
2016-02-10 20:30:38 +09:00
namespace Textamina.Markdig.Syntax
2016-02-10 20:30:38 +09:00
{
2016-02-17 01:00:26 +09:00
public sealed class StringLine
2016-02-10 20:30:38 +09:00
{
public StringLine(string text)
{
if (text == null) throw new ArgumentNullException(nameof(text));
Text = text;
Start = 0;
End = Text.Length - 1;
Column = 0;
SpaceHeaderCount = 0;
Current = End >= 0 ? Text[0] : (char)0;
}
public string Text { get; private set; }
2016-02-10 20:30:38 +09:00
public int Start { get; set; }
2016-02-16 21:03:44 +09:00
public int End { get; set; }
2016-02-10 20:30:38 +09:00
public int SpaceHeaderCount { get; set; }
public int Column { get; private set; }
2016-02-10 20:30:38 +09:00
public char Current { get; private set; }
public bool IsEol => Start > End;
2016-02-10 20:30:38 +09:00
private bool isBlankLine;
public char this[int index] => Text[index];
public State Save()
{
return new State(Start, End, Column, SpaceHeaderCount, Current);
}
2016-02-16 22:42:40 +09:00
public void Restore(State state)
{
Restore(ref state);
}
public void Restore(ref State state)
{
Start = state.Start;
End = state.End;
Column = state.Column;
SpaceHeaderCount = state.SpaceHeaderCount;
Current = state.Current;
}
2016-02-10 20:30:38 +09:00
[MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
public char NextChar()
{
Start++;
if (Start <= End)
2016-02-10 20:30:38 +09:00
{
// If previous character was a tab make the Column += 4
Column++;
if (CharHelper.IsTab(Current))
2016-02-10 20:30:38 +09:00
{
// Align the tab on a column
Column = ((Column + 3) / 4) * 4;
2016-02-10 20:30:38 +09:00
}
Current = Text[Start];
2016-02-10 20:30:38 +09:00
}
else
{
Start = End + 1;
2016-02-10 20:30:38 +09:00
Current = (char) 0;
}
return Current;
}
2016-02-16 22:42:40 +09:00
[MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
public char PeekChar(int offset)
{
var index = Start + offset;
return index <= End ? Text[index] : (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;
2016-02-16 22:42:40 +09:00
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;
}
2016-02-16 22:42:40 +09:00
public bool Search(string text, int offset = 0)
{
var end = End - text.Length + 1;
2016-02-16 22:42:40 +09:00
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;
}
2016-02-10 20:30:38 +09:00
[MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
public bool IsBlankLine()
{
if (isBlankLine)
{
return true;
}
for (int i = Start; i <= End; i++)
2016-02-10 20:30:38 +09:00
{
if (!CharHelper.IsSpace(Text[i]))
2016-02-10 20:30:38 +09:00
{
return false;
}
}
isBlankLine = true;
return true;
}
2016-02-16 22:42:40 +09:00
public void SkipLeadingSpaces3()
2016-02-10 20:30:38 +09:00
{
2016-02-16 22:42:40 +09:00
for (int i = 0; i < 3; i++)
2016-02-10 20:30:38 +09:00
{
if (!CharHelper.IsSpace(Current))
2016-02-10 20:30:38 +09:00
{
2016-02-16 22:42:40 +09:00
break;
2016-02-10 20:30:38 +09:00
}
NextChar();
}
}
2016-02-17 01:20:42 +09:00
public StringSlice ToSlice()
{
return new StringSlice(Text, Start, End);
}
public void TrimStart()
{
// Strip leading spaces
var c = Current;
while (CharHelper.IsSpace(c))
{
c = NextChar();
}
}
public void TrimEnd()
{
for (int i = End; i >= Start; i--)
{
End = i;
if (!CharHelper.IsSpace(this[i]))
{
break;
}
}
}
public void Trim()
{
TrimStart();
TrimEnd();
}
2016-02-10 20:30:38 +09:00
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;
2016-02-10 20:30:38 +09:00
}
}
}