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

204 lines
5.5 KiB
C#
Raw Normal View History

2016-02-25 20:30:37 +09:00
using System;
2016-02-26 22:06:59 +09:00
using System.Collections;
using System.Collections.Generic;
2016-02-25 20:30:37 +09:00
using System.Text;
using Textamina.Markdig.Helpers;
namespace Textamina.Markdig.Syntax
{
public class StringLineGroup : IEnumerable
2016-02-25 20:30:37 +09:00
{
private static readonly StringLine[] Empty = new StringLine[0];
2016-02-25 20:30:37 +09:00
public StringLineGroup()
2016-02-25 20:30:37 +09:00
{
Lines = Empty;
2016-02-25 20:30:37 +09:00
}
public StringLineGroup(string text)
2016-02-25 20:30:37 +09:00
{
if (text == null) throw new ArgumentNullException(nameof(text));
Lines = Empty;
2016-02-26 22:06:59 +09:00
Add(new StringSlice(text));
2016-02-25 20:30:37 +09:00
}
public StringLine[] Lines { get; private set; }
2016-02-25 20:30:37 +09:00
public int Count { get; private set; }
2016-02-25 20:30:37 +09:00
2016-02-27 00:13:01 +09:00
public void Clear()
{
Array.Clear(Lines, 0, Lines.Length);
2016-02-27 00:13:01 +09:00
Count = 0;
}
public void RemoveAt(int index)
{
if (Count - 1 == index)
{
Count--;
}
else
{
Array.Copy(Lines, index + 1, Lines, index, Count - index - 1);
Lines[Count - 1] = new StringLine();
2016-02-27 00:13:01 +09:00
Count--;
}
}
public void Add(ref StringLine line)
2016-02-25 20:30:37 +09:00
{
if (Count == Lines.Length) IncreaseCapacity();
Lines[Count++] = line;
2016-02-25 20:30:37 +09:00
}
2016-02-26 22:06:59 +09:00
public void Add(StringSlice slice)
2016-02-25 20:30:37 +09:00
{
if (Count == Lines.Length) IncreaseCapacity();
Lines[Count++] = new StringLine(ref slice);
2016-02-25 20:30:37 +09:00
}
private void IncreaseCapacity()
{
int newCapacity = Lines.Length == 0 ? 4 : Lines.Length * 2;
var newItems = new StringLine[newCapacity];
2016-02-25 20:30:37 +09:00
if (Count > 0)
{
Array.Copy(Lines, 0, newItems, 0, Count);
2016-02-25 20:30:37 +09:00
}
Lines = newItems;
2016-02-25 20:30:37 +09:00
}
public override string ToString()
{
return ToSlice().ToString();
}
public StringSlice ToSlice(List<int> lineOffsets = null)
2016-02-25 20:30:37 +09:00
{
if (Count == 0)
{
if (lineOffsets != null)
{
lineOffsets.Add(1);
}
return new StringSlice(string.Empty);
}
if (Count == 1)
{
if (lineOffsets != null)
{
lineOffsets.Add(Lines[0].Slice.End + 1);
}
return Lines[0];
}
2016-02-26 07:35:49 +09:00
2016-02-25 22:10:52 +09:00
var builder = StringBuilderCache.Local();
int lineOffset = 0;
2016-02-26 07:35:49 +09:00
for (int i = 0; i < Count; i++)
2016-02-25 20:30:37 +09:00
{
if (i > 0)
{
if (lineOffsets != null)
{
2016-02-28 21:23:40 +09:00
lineOffsets.Add(builder.Length + 2); // Add 1 for \n and 1 for next line
}
builder.Append('\n');
2016-02-25 20:30:37 +09:00
}
if (!Lines[i].Slice.IsEmpty)
2016-02-26 20:42:28 +09:00
{
builder.Append(Lines[i].Slice.Text, Lines[i].Slice.Start, Lines[i].Slice.Length);
2016-02-26 20:42:28 +09:00
}
}
if (lineOffsets != null)
{
2016-02-28 21:23:40 +09:00
lineOffsets.Add(builder.Length + 1); // Add 1 for \0
2016-02-25 20:30:37 +09:00
}
2016-02-25 22:10:52 +09:00
var str = builder.ToString();
builder.Clear();
return new StringSlice(str);
2016-02-25 20:30:37 +09:00
}
2016-02-26 22:06:59 +09:00
IEnumerator IEnumerable.GetEnumerator()
{
return Lines.GetEnumerator();
2016-02-26 22:06:59 +09:00
}
public Iterator ToCharIterator()
{
return new Iterator(this);
}
public struct Iterator : ICharIterator
{
private readonly StringLineGroup lines;
2016-02-26 22:06:59 +09:00
private int offset;
public Iterator(StringLineGroup lines)
2016-02-26 22:06:59 +09:00
{
this.lines = lines;
Start = -1;
offset = -1;
SliceIndex = 0;
CurrentChar = '\0';
End = -2;
for (int i = 0; i < lines.Count; i++)
{
End += lines.Lines[i].Slice.Length + 1; // Add chars
2016-02-26 22:06:59 +09:00
}
NextChar();
}
public int Start { get; private set; }
public char CurrentChar { get; private set; }
public int End { get; private set; }
2016-02-27 00:13:01 +09:00
public bool IsEmpty => Start > End;
2016-02-26 22:06:59 +09:00
public int SliceIndex { get; private set; }
public char NextChar()
{
Start++;
offset++;
if (Start <= End)
{
var slice = (StringSlice)lines.Lines[SliceIndex];
2016-02-26 22:06:59 +09:00
if (offset < slice.Length)
{
CurrentChar = slice[slice.Start + offset];
}
else
{
CurrentChar = '\n';
SliceIndex++;
offset = -1;
}
}
else
{
CurrentChar = '\0';
Start = End + 1;
SliceIndex = lines.Count;
offset--;
}
return CurrentChar;
}
public bool TrimStart()
{
var c = CurrentChar;
2016-02-27 00:13:01 +09:00
bool hasSpaces = false;
2016-02-26 22:06:59 +09:00
while (c.IsWhitespace())
{
2016-02-27 00:13:01 +09:00
hasSpaces = true;
2016-02-26 22:06:59 +09:00
c = NextChar();
}
2016-02-27 00:13:01 +09:00
return hasSpaces;
2016-02-26 22:06:59 +09:00
}
}
2016-02-25 20:30:37 +09:00
}
}