restructured MarkupTokenizer a bit.

This commit is contained in:
Nils Andresen 2022-08-03 22:24:49 +02:00 committed by Patrik Svensson
parent 540bc1307c
commit 00a9ba325e
2 changed files with 123 additions and 90 deletions

View File

@ -24,134 +24,154 @@ internal sealed class MarkupTokenizer : IDisposable
}
var current = _reader.Peek();
if (current == '[')
return current == '[' ? ReadMarkup() : ReadText();
}
private bool ReadText()
{
var position = _reader.Position;
var builder = new StringBuilder();
var encounteredClosing = false;
while (!_reader.Eof)
{
var position = _reader.Position;
_reader.Read();
if (_reader.Eof)
{
throw new InvalidOperationException($"Encountered malformed markup tag at position {_reader.Position}.");
}
current = _reader.Peek();
var current = _reader.Peek();
if (current == '[')
{
// markup encountered. Stop processing.
break;
}
// If we find a closing tag (']') there must be two of them.
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;
}
private bool ReadMarkup()
{
var position = _reader.Position;
_reader.Read();
if (_reader.Eof)
{
throw new InvalidOperationException($"Encountered malformed markup tag at position {_reader.Position}.");
}
var current = _reader.Peek();
switch (current)
{
case '[':
// No markup but instead escaped markup in text.
_reader.Read();
Current = new MarkupToken(MarkupTokenKind.Text, "[", position);
return true;
}
if (current == '/')
{
case '/':
// Markup closed.
_reader.Read();
if (_reader.Eof)
{
throw new InvalidOperationException($"Encountered malformed markup tag at position {_reader.Position}.");
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}.");
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)
// Read the "content" of the markup until we find the end-of-markup
var builder = new StringBuilder();
var encounteredOpening = false;
var encounteredClosing = false;
while (!_reader.Eof)
{
current = _reader.Peek();
if (current == ']' && !encounteredOpening)
{
current = _reader.Read();
var next = '\0';
if (!_reader.Eof)
{
next = _reader.Peek();
}
if (current == ']')
{
if (next != ']')
{
break;
}
_reader.Read();
}
builder.Append(current);
if (current != '[')
if (encounteredClosing)
{
builder.Append(_reader.Read());
encounteredClosing = false;
continue;
}
if (next == '[')
{
_reader.Read();
}
else
{
throw new InvalidOperationException(
$"Encountered malformed markup tag at position {_reader.Position - 1}.");
}
_reader.Read();
encounteredClosing = true;
continue;
}
if (_reader.Eof)
if (current == '[' && !encounteredClosing)
{
throw new InvalidOperationException($"Encountered malformed markup tag at position {_reader.Position}.");
}
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 == '[')
if (encounteredOpening)
{
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());
encounteredOpening = false;
continue;
}
builder.Append(_reader.Read());
_reader.Read();
encounteredOpening = true;
continue;
}
if (encounteredClosing)
{
throw new InvalidOperationException($"Encountered unescaped ']' token at position {_reader.Position}.");
break;
}
Current = new MarkupToken(MarkupTokenKind.Text, builder.ToString(), position);
return true;
if (encounteredOpening)
{
throw new InvalidOperationException(
$"Encountered malformed markup tag at position {_reader.Position - 1}.");
}
builder.Append(_reader.Read());
}
if (_reader.Eof)
{
throw new InvalidOperationException($"Encountered malformed markup tag at position {_reader.Position}.");
}
Current = new MarkupToken(MarkupTokenKind.Open, builder.ToString(), position);
return true;
}
}

View File

@ -141,5 +141,18 @@ public partial class AnsiConsoleTests
result.ShouldBeOfType<InvalidOperationException>()
.Message.ShouldBe("Encountered closing tag when none was expected near position 5.");
}
[Fact]
public void Should_Not_Get_Confused_When_Mixing_Escaped_And_Unescaped()
{
// Given
var console = new TestConsole();
// When
console.Markup("[grey][[grey]][/][white][[white]][/]");
// Then
console.Output.ShouldBe("[grey][white]");
}
}
}