Skip to content

Commit

Permalink
deal with peculiar wrapping behavior when emitting characters in the …
Browse files Browse the repository at this point in the history
…last column
  • Loading branch information
doubleyewdee committed Nov 23, 2018
1 parent 684f1be commit 1162c9f
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 40 deletions.
16 changes: 0 additions & 16 deletions ConsoleBuffer.sln
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleBuffer", "src\Consol
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "condo", "src\condo\condo.csproj", "{D890EB09-11B9-41A8-B9A7-C1D159312A32}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "condo.uwp", "src\condo.uwp\condo.uwp.csproj", "{FB9FD3E5-EDF1-4924-8945-42DC0AFE478F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleBufferTests", "test\ConsoleBufferTests\ConsoleBufferTests.csproj", "{D11953E5-195F-43F4-9109-DE93CED6D016}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F3383E1A-F55C-405B-91BD-00C11E285D2D}"
Expand Down Expand Up @@ -60,20 +58,6 @@ Global
{D890EB09-11B9-41A8-B9A7-C1D159312A32}.Release|x64.Build.0 = Debug|Any CPU
{D890EB09-11B9-41A8-B9A7-C1D159312A32}.Release|x86.ActiveCfg = Debug|Any CPU
{D890EB09-11B9-41A8-B9A7-C1D159312A32}.Release|x86.Build.0 = Debug|Any CPU
{FB9FD3E5-EDF1-4924-8945-42DC0AFE478F}.Debug|Any CPU.ActiveCfg = Debug|x86
{FB9FD3E5-EDF1-4924-8945-42DC0AFE478F}.Debug|ARM.ActiveCfg = Debug|ARM
{FB9FD3E5-EDF1-4924-8945-42DC0AFE478F}.Debug|ARM.Build.0 = Debug|ARM
{FB9FD3E5-EDF1-4924-8945-42DC0AFE478F}.Debug|ARM.Deploy.0 = Debug|ARM
{FB9FD3E5-EDF1-4924-8945-42DC0AFE478F}.Debug|x64.ActiveCfg = Debug|x64
{FB9FD3E5-EDF1-4924-8945-42DC0AFE478F}.Debug|x64.Build.0 = Debug|x64
{FB9FD3E5-EDF1-4924-8945-42DC0AFE478F}.Debug|x64.Deploy.0 = Debug|x64
{FB9FD3E5-EDF1-4924-8945-42DC0AFE478F}.Debug|x86.ActiveCfg = Debug|x86
{FB9FD3E5-EDF1-4924-8945-42DC0AFE478F}.Debug|x86.Build.0 = Debug|x86
{FB9FD3E5-EDF1-4924-8945-42DC0AFE478F}.Debug|x86.Deploy.0 = Debug|x86
{FB9FD3E5-EDF1-4924-8945-42DC0AFE478F}.Release|Any CPU.ActiveCfg = Debug|x86
{FB9FD3E5-EDF1-4924-8945-42DC0AFE478F}.Release|ARM.ActiveCfg = Debug|x86
{FB9FD3E5-EDF1-4924-8945-42DC0AFE478F}.Release|x64.ActiveCfg = Debug|x86
{FB9FD3E5-EDF1-4924-8945-42DC0AFE478F}.Release|x86.ActiveCfg = Debug|x86
{D11953E5-195F-43F4-9109-DE93CED6D016}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D11953E5-195F-43F4-9109-DE93CED6D016}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D11953E5-195F-43F4-9109-DE93CED6D016}.Debug|ARM.ActiveCfg = Debug|Any CPU
Expand Down
71 changes: 49 additions & 22 deletions src/ConsoleBuffer/Buffer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,25 @@ public sealed class Buffer : INotifyPropertyChanged

private short cursorX;
private short cursorY;
private short MaxCursorX => (short)(this.Width - 1);
private short MaxCursorY => (short)(this.Height - 1);

private long receivedCharacters;
private long wrapCharacter;
private int currentChar;

/// <summary>
/// we store X/Y as 0-offset indexes for convenience. escape codes will pass these around as 1-offset (top left is 1,1)
/// and we'll translate that nonsense where we have to.
/// </summary>
public (short X, short Y) CursorPosition => (this.cursorX, this.cursorY);
/// <summary>
/// True if the cursor is currently visible.
/// </summary>
public bool CursorVisible { get; private set; }
/// <summary>
/// True if the cursor should be blinking.
/// </summary>
public bool CursorBlink { get; private set; }

private int topVisibleLine;
Expand All @@ -31,7 +43,13 @@ private int CurrentLine
}
}

/// <summary>
/// Width of the console in characters.
/// </summary>
public short Width { get; set; }
/// <summary>
/// Height of the console in characters.
/// </summary>
public short Height { get; set; }

public string Title { get; private set; }
Expand All @@ -48,7 +66,7 @@ public Buffer(short width, short height)
this.lines.PushBack(new Line(null));
}
this.topVisibleLine = 0;
this.bottomVisibleLine = this.Height - 1;
this.bottomVisibleLine = this.MaxCursorY;
}

public void Append(byte[] bytes, int length)
Expand All @@ -59,6 +77,7 @@ public void Append(byte[] bytes, int length)
{
if (!this.AppendChar(bytes[i])) continue;

++this.receivedCharacters;
switch (this.parser.Append(this.currentChar))
{
case ParserAppendResult.Render:
Expand Down Expand Up @@ -86,19 +105,32 @@ public void Append(byte[] bytes, int length)
/// <param name="ch"></param>
private void RenderAtCursor(int ch)
{
this.lines[this.CurrentLine].Set(this.cursorX, new Character { Glyph = ch });
++this.cursorX;
if (this.cursorX == this.Width)

if (this.cursorX == this.MaxCursorX && this.wrapCharacter == this.receivedCharacters - 1)
{
this.cursorX = 0;
if (this.cursorY == this.Height - 1)
if (this.cursorY == this.MaxCursorY)
{
this.ScrollDown();
}
else
{
++this.cursorY;
}
this.cursorX = 0;
this.wrapCharacter = -1;
}

this.lines[this.CurrentLine].Set(this.cursorX, new Character { Glyph = ch });
if (this.cursorX == this.MaxCursorX)
{
// if we hit the end of line and our next character is also printable or a backspace we will do an implicit line-wrap.
// in the appropriate direction. this seems to conform with the expected behavior of applications which emit a variety
// of control characters/etc to ensure this wiggly state is resolved appropriately.
this.wrapCharacter = this.receivedCharacters;
}
else
{
++this.cursorX;
}
}

Expand Down Expand Up @@ -148,18 +180,13 @@ private void HandleControlCharacter(Commands.ControlCharacter.ControlCode code)
// XXX: need to raise a beep event.
break;
case Commands.ControlCharacter.ControlCode.BS:
// backspace wrap to previous line if not on first line, if we're at 0,0 we go nowhere.
if (this.cursorX == 0)
if (this.cursorX == this.MaxCursorX && this.wrapCharacter == this.receivedCharacters - 1)
{
if (this.cursorY > 0)
{
--this.cursorY;
this.cursorX = (short)(this.Width - 1);
}
// do nothing, terminal expected us to wrap.
}
else
{
--this.cursorX;
this.cursorX = (short)Math.Max(0, this.cursorX - 1);
}
break;
case Commands.ControlCharacter.ControlCode.CR:
Expand All @@ -172,11 +199,11 @@ private void HandleControlCharacter(Commands.ControlCharacter.ControlCode code)
this.ScrollDown();
}

this.cursorY = (short)Math.Min(this.Height - 1, this.cursorY + 1);
this.cursorY = (short)Math.Min(this.MaxCursorY, this.cursorY + 1);
break;
case Commands.ControlCharacter.ControlCode.TAB:
// XXX: we don't handle commands to set tab stops yet but I guess need to do so at some point!
this.cursorX = (short)Math.Max(this.Width - 1, (this.cursorX + 8 - (this.cursorX % 8)));
this.cursorX = (short)Math.Max(this.MaxCursorX, (this.cursorX + 8 - (this.cursorX % 8)));
break;
default:
// XXX: should log the sequence.
Expand Down Expand Up @@ -220,13 +247,13 @@ private void HandleCursorMove(Commands.CursorMove cu)
this.cursorY = (short)Math.Max(0, this.cursorY - cu.Count);
break;
case Commands.CursorMove.CursorDirection.Down:
this.cursorY = (short)Math.Min(this.Height - 1, this.cursorY + cu.Count);
this.cursorY = (short)Math.Min(this.MaxCursorY, this.cursorY + cu.Count);
break;
case Commands.CursorMove.CursorDirection.Backward:
this.cursorX = (short)Math.Max(0, this.cursorX - cu.Count);
break;
case Commands.CursorMove.CursorDirection.Forward:
this.cursorX = (short)Math.Min(this.Width - 1, this.cursorX + cu.Count);
this.cursorX = (short)Math.Min(this.MaxCursorX, this.cursorX + cu.Count);
break;
}
}
Expand Down Expand Up @@ -285,15 +312,15 @@ private void HandleEraseInLine(Commands.EraseIn eil)
{
case Commands.EraseIn.Parameter.All:
startX = 0;
endX = this.Width - 1;
endX = this.MaxCursorX;
break;
case Commands.EraseIn.Parameter.Before:
startX = 0;
endX = this.cursorX;
break;
case Commands.EraseIn.Parameter.After:
startX = this.cursorX;
endX = this.Width - 1;
endX = this.MaxCursorX;
break;
default:
return;
Expand All @@ -309,11 +336,11 @@ private void HandleSetCursorPosition(Commands.SetCursorPosition scp)
{
if (scp.PosX > -1)
{
this.cursorX = (short)Math.Min(this.Width - 1, scp.PosX);
this.cursorX = (short)Math.Min(this.MaxCursorX, scp.PosX);
}
if (scp.PosY > -1)
{
this.cursorY = (short)Math.Min(this.Height - 1, scp.PosY);
this.cursorY = (short)Math.Min(this.MaxCursorY, scp.PosY);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/condo/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public MainWindow()

private void OnLoaded(object sender, RoutedEventArgs e)
{
this.console = TerminalManager.Instance.GetOrCreate(0, "bash.exe");
this.console = TerminalManager.Instance.GetOrCreate(0, "wsl.exe");
this.keyHandler = new KeyHandler(this.console);

this.screen = new Screen(this.console);
Expand Down
2 changes: 1 addition & 1 deletion test/ConsoleBufferTests/ConsoleBufferTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.8.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
<PackageReference Include="MSTest.TestAdapter" Version="1.3.2" />
<PackageReference Include="MSTest.TestFramework" Version="1.3.2" />
</ItemGroup>
Expand Down

0 comments on commit 1162c9f

Please sign in to comment.