mirror of
https://github.com/nsnail/spectre.console.git
synced 2025-04-16 00:42:51 +08:00
137 lines
4.1 KiB
C#
137 lines
4.1 KiB
C#
using System;
|
|
using System.Text;
|
|
|
|
namespace Spectre.Console.Internal
|
|
{
|
|
internal sealed class MarkupTokenizer : IDisposable
|
|
{
|
|
private readonly StringBuffer _reader;
|
|
|
|
public MarkupToken? Current { get; private set; }
|
|
|
|
public MarkupTokenizer(string text)
|
|
{
|
|
_reader = new StringBuffer(text ?? throw new ArgumentNullException(nameof(text)));
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
_reader.Dispose();
|
|
}
|
|
|
|
public bool MoveNext()
|
|
{
|
|
if (_reader.Eof)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
var current = _reader.Peek();
|
|
if (current == '[')
|
|
{
|
|
var position = _reader.Position;
|
|
|
|
_reader.Read();
|
|
|
|
if (_reader.Eof)
|
|
{
|
|
throw new InvalidOperationException($"Encountered malformed markup tag at position {_reader.Position}.");
|
|
}
|
|
|
|
current = _reader.Peek();
|
|
if (current == '[')
|
|
{
|
|
_reader.Read();
|
|
Current = new MarkupToken(MarkupTokenKind.Text, "[", position);
|
|
return true;
|
|
}
|
|
|
|
if (current == '/')
|
|
{
|
|
_reader.Read();
|
|
|
|
if (_reader.Eof)
|
|
{
|
|
throw new InvalidOperationException($"Encountered malformed markup tag at position {_reader.Position}.");
|
|
}
|
|
|
|
current = _reader.Peek();
|
|
if (current != ']')
|
|
{
|
|
throw new InvalidOperationException($"Encountered malformed markup tag at position {_reader.Position}.");
|
|
}
|
|
|
|
_reader.Read();
|
|
Current = new MarkupToken(MarkupTokenKind.Close, string.Empty, position);
|
|
return true;
|
|
}
|
|
|
|
var builder = new StringBuilder();
|
|
while (!_reader.Eof)
|
|
{
|
|
current = _reader.Peek();
|
|
if (current == ']')
|
|
{
|
|
break;
|
|
}
|
|
|
|
builder.Append(_reader.Read());
|
|
}
|
|
|
|
if (_reader.Eof)
|
|
{
|
|
throw new InvalidOperationException($"Encountered malformed markup tag at position {_reader.Position}.");
|
|
}
|
|
|
|
_reader.Read();
|
|
Current = new MarkupToken(MarkupTokenKind.Open, builder.ToString(), position);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
var position = _reader.Position;
|
|
var builder = new StringBuilder();
|
|
|
|
var encounteredClosing = false;
|
|
while (!_reader.Eof)
|
|
{
|
|
current = _reader.Peek();
|
|
if (current == '[')
|
|
{
|
|
break;
|
|
}
|
|
else if (current == ']')
|
|
{
|
|
if (encounteredClosing)
|
|
{
|
|
_reader.Read();
|
|
encounteredClosing = false;
|
|
continue;
|
|
}
|
|
|
|
encounteredClosing = true;
|
|
}
|
|
else
|
|
{
|
|
if (encounteredClosing)
|
|
{
|
|
throw new InvalidOperationException(
|
|
$"Encountered unescaped ']' token at position {_reader.Position}");
|
|
}
|
|
}
|
|
|
|
builder.Append(_reader.Read());
|
|
}
|
|
|
|
if (encounteredClosing)
|
|
{
|
|
throw new InvalidOperationException($"Encountered unescaped ']' token at position {_reader.Position}");
|
|
}
|
|
|
|
Current = new MarkupToken(MarkupTokenKind.Text, builder.ToString(), position);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|