Skip to content

Commit

Permalink
start very basic work on actually parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
doubleyewdee committed Nov 14, 2018
1 parent 4315430 commit 4e84e82
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 16 deletions.
86 changes: 86 additions & 0 deletions src/ConsoleBuffer/AnsiParser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
namespace ConsoleBuffer
{
enum ParserAppendResult
{
/// <summary>
/// Sequence incomplete.
/// </summary>
Pending = 0,
/// <summary>
/// Sequence complete, parser is ready to query for command.
/// </summary>
Complete,
/// <summary>
/// Sequence terminated due to invalid/unexpected terminator.
/// </summary>
Invalid,
/// <summary>
/// Character is not part of a parsing sequence and may be rendered.
/// </summary>
Render,
/// <summary>
/// Invalid parser state, should not occur.
/// </summary>
None,
}

enum ParserCommand
{
/// <summary>
/// Line-feed (\n)
/// </summary>
LF = 0,
/// <summary>
/// Carriage return (\r)
/// </summary>
CR,
}

sealed class AnsiParser
{
enum SequenceType
{
/// <summary>
/// Indicates we are in a standard (\033) escape sequence.
/// </summary>
Standard = 0,
/// <summary>
/// Indicates we are in an operating system (\033 ]) escape sequence.
/// </summary>
OSCommand,
/// <summary>
/// We are not in a sequence.
/// </summary>
None,
}
private SequenceType sequenceType = SequenceType.None;
private bool inSequence = false;

public ParserCommand CurrentCommand { get; private set; }

public AnsiParser()
{
}

public ParserAppendResult Append(int character)
{
switch (this.sequenceType)
{
case SequenceType.None:
switch (character)
{
case '\n':
this.CurrentCommand = ParserCommand.LF;
return ParserAppendResult.Complete;
case '\r':
this.CurrentCommand = ParserCommand.CR;
return ParserAppendResult.Complete;
default:
return ParserAppendResult.Render;
}
}

return ParserAppendResult.None; // should be unreachable.
}
}
}
47 changes: 31 additions & 16 deletions src/ConsoleBuffer/Buffer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

public sealed class Buffer : INotifyPropertyChanged
{
private readonly AnsiParser parser = new AnsiParser();
private readonly List<Line> lines = new List<Line>();
private readonly object renderLock = new object();

Expand Down Expand Up @@ -49,24 +50,18 @@ public void Append(byte[] bytes, int length)
{
if (!this.AppendChar(bytes[i])) continue;

if (this.currentChar == '\n')
switch (this.parser.Append(this.currentChar))
{
Logger.Verbose($"newline (current: {this.lines[this.currentLine]})");
if (this.currentLine == this.lines.Count - 1)
{
this.lines.Add(new Line());
}

this.cursorY = (short)Math.Min(this.Height - 1, this.cursorY + 1);
}
else if (this.currentChar == '\r')
{
Logger.Verbose($"carriage return");
this.cursorX = 0;
case ParserAppendResult.Render:
this.lines[this.currentLine].Set(this.cursorX, new Character { Glyph = this.currentChar });
this.cursorX = (short)Math.Min(this.Width - 1, this.cursorX + 1);
break;
case ParserAppendResult.Complete:
this.ExecuteParserCommand();
break;
default:
throw new InvalidOperationException("unexpected parser result");
}

this.lines[this.currentLine].Set(this.cursorX, new Character { Glyph = this.currentChar });
this.cursorX = (short)Math.Min(this.Width - 1, this.cursorX + 1);
}
}
}
Expand All @@ -82,6 +77,26 @@ private bool AppendChar(byte b)
return true;
}

private void ExecuteParserCommand()
{
switch (this.parser.CurrentCommand)
{
case ParserCommand.LF:
if (this.currentLine == this.lines.Count - 1)
{
this.lines.Add(new Line());
}

this.cursorY = (short)Math.Min(this.Height - 1, this.cursorY + 1);
break;
case ParserCommand.CR:
this.cursorX = 0;
break;
default:
throw new InvalidOperationException($"Unexpected parser command {this.parser.CurrentCommand}");
}
}

/// <summary>
/// Render character-by-character onto the specified target.
/// </summary>
Expand Down

0 comments on commit 4e84e82

Please sign in to comment.