Skip to content

Commit

Permalink
SGR work-in-progress, add xterm palette and start the wrapping work
Browse files Browse the repository at this point in the history
  • Loading branch information
doubleyewdee committed Nov 25, 2018
1 parent 7ef6432 commit 83d602c
Show file tree
Hide file tree
Showing 13 changed files with 4,405 additions and 9 deletions.
8 changes: 8 additions & 0 deletions src/ConsoleBuffer/Buffer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,9 @@ private void HandleControlSequence(Commands.ControlSequence cmd)
case Commands.SetCursorPosition scp:
this.HandleSetCursorPosition(scp);
break;
case Commands.SetGraphicsRendition sgr:
this.HandleSGR(sgr);
break;
case Commands.SetMode sm:
this.HandleSetMode(sm);
break;
Expand Down Expand Up @@ -354,6 +357,11 @@ private void HandleSetCursorPosition(Commands.SetCursorPosition scp)
}
}

private void HandleSGR(Commands.SetGraphicsRendition sgr)
{

}

private void HandleSetMode(Commands.SetMode sm)
{
switch (sm.Setting)
Expand Down
140 changes: 139 additions & 1 deletion src/ConsoleBuffer/Character.cs
Original file line number Diff line number Diff line change
@@ -1,21 +1,159 @@
namespace ConsoleBuffer
{
using System;

// XXX: Gonna end up with a lot of these and they're really freakin' big.
// could consider a morphable type with different sizes to avoid the (currently) 12 bytes-per-character issue.
// on a 'normal' 80x25 terminal the current buffer alone is just >23kB. A 160 character wide buffer with a 32k
// line scrollback is nearly 60MB. Per buffer. Not an issue now but something we should care about and fix in
// the future.
public struct Character
{
[Flags]
public enum Options : byte
{
None = 0x00,
// we have 3 color bits which combine to represent the 8 "basic" colors of classic terminals
ColorBits = 0x07, // (0x01, 0x02, 0x04)
Black = 0x00,
Red = 0x01,
Green = 0x02,
Yellow = 0x03,
Blue = 0x04,
Magenta = 0x05,
Cyan = 0x06,
White = 0x07,

// we use 3 additional bits (currently) for flags
FlagBits = 0x38, // (0x08, 0x10, 0x20)
Bright = 0x08,
Underline = 0x10,
Inverse = 0x20,
Extended = 0x18,
// 0x28 free
// 0x38 free

// 0x40, 0x80 free bits
}

public struct ColorInfo
{
public byte R;
public byte G;
public byte B;
public Options Options;

public bool Bright
{
get
{
return ((byte)this.Options & (byte)Options.Bright) == (byte)Options.Bright;
}
set
{
if (value)
{
this.Options = (Options)((byte)this.Options | (byte)Options.Bright);
}
else
{
this.Options = (Options)((byte)this.Options & ~(byte)Options.Bright);
}
}
}

/// <summary>
/// Whether the underline bit is set. Should not apply to background colors.
/// </summary>
public bool Underline
{
get
{
return ((byte)this.Options & (byte)Options.Underline) == (byte)Options.Underline;
}
set
{
if (value)
{
this.Options = (Options)((byte)this.Options | (byte)Options.Underline);
}
else
{
this.Options = (Options)((byte)this.Options & ~(byte)Options.Underline);
}
}
}

/// <summary>
/// Whether the 'inverse' bit is set. Should not apply to background colors.
/// </summary>
public bool Inverse
{
get
{
return ((byte)this.Options & (byte)Options.Inverse) == (byte)Options.Inverse;
}
set
{
if (value)
{
this.Options = (Options)((byte)this.Options | (byte)Options.Inverse);
}
else
{
this.Options = (Options)((byte)this.Options & ~(byte)Options.Inverse);
}
}
}

/// <summary>
/// Whether extended (RGB) color values should be applied for this cell.
/// </summary>
public bool Extended
{
get
{
return ((byte)this.Options & (byte)Options.Extended) == (byte)Options.Extended;
}
set
{
if (value)
{
this.Options = (Options)((byte)this.Options | (byte)Options.Extended);
}
else
{
this.Options = (Options)((byte)this.Options & ~(byte)Options.Extended);
}
}
}

/// <summary>
/// Classic color value.
/// </summary>
public Options BasicColor
{
get
{
return (Options)((byte)this.Options & (byte)Options.ColorBits);
}
set
{
var colorValue = (byte)value & (byte)Options.ColorBits;
var colorlessOptions = (byte)this.Options & ~(byte)Options.ColorBits;
this.Options = (Options)(colorlessOptions & colorValue);
}
}

/// <summary>
/// True if there is any classic color value set.
/// </summary>
public bool HasBasicColor => ((byte)this.Options & (byte)Options.ColorBits) != 0;
}

public ColorInfo Foreground { get; set; }
public ColorInfo Background { get; set; }
public int Glyph { get; set; } // XXX: a single int isn't quite sufficient to represent emoji with ZWJ. fix later.

public int Glyph { get; set; } // XXX: a single int isn't sufficient to represent emoji with ZWJ. fix later.
}
}
2 changes: 2 additions & 0 deletions src/ConsoleBuffer/Commands/ControlSequence.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ public static Base Create(char command, string bufferData)
return new EraseIn(bufferData, EraseIn.EraseType.Display);
case 'K':
return new EraseIn(bufferData, EraseIn.EraseType.Line);
case 'm':
return new SetGraphicsRendition(bufferData);
case 'X':
return new EraseCharacter(bufferData);
}
Expand Down
29 changes: 29 additions & 0 deletions src/ConsoleBuffer/Commands/SetGraphicsRendition.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
namespace ConsoleBuffer.Commands
{
public sealed class SetGraphicsRendition : ControlSequence
{
public enum FlagValue
{
Set,
Unset,
None,
}

public bool HaveForeground { get; private set; }
public Character.ColorInfo ForegroundColor { get; private set; }

public bool HaveBackground { get; private set; }
public Character.ColorInfo BackgroundColor { get; private set; }

public FlagValue Bold { get; private set; }
public FlagValue Underline { get; private set; }
public FlagValue Inverse { get; private set; }

public SetGraphicsRendition(string bufferData) : base(bufferData)
{
this.Bold = FlagValue.None;
this.Underline = FlagValue.None;
this.Inverse = FlagValue.None;
}
}
}
5 changes: 5 additions & 0 deletions src/ConsoleBuffer/ConsoleBuffer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,9 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<None Update="xterm-colors.json">
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
10 changes: 3 additions & 7 deletions src/ConsoleBuffer/ConsoleWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public ConsoleWrapper(string command)
this.InitializeStartupInfo();
this.StartProcess();

Task.Run(() => this.ReadConsoleTask());
Task.Factory.StartNew(() => this.ReadConsoleTask(), TaskCreationOptions.LongRunning);
this.writeStream = new FileStream(this.writeHandle, FileAccess.Write);
}

Expand Down Expand Up @@ -159,7 +159,7 @@ private void StartProcess()
this.Running = true;
this.OnPropertyChanged(nameof(this.Running));

Task.Run(() =>
Task.Factory.StartNew(() =>
{
var ret = NativeMethods.WaitForSingleObject(this.processInfo.hProcess, uint.MaxValue);
if (ret != 0)
Expand All @@ -176,11 +176,7 @@ private void StartProcess()
this.ProcessExitCode = exitCode;
this.Running = false;
this.OnPropertyChanged(nameof(this.Running));
// XXX: long-term I think we should have the presentation layer do this but let's dump it here for now
var msg = Encoding.UTF8.GetBytes($"\r\n[process terminated with code {exitCode}.]");
this.Buffer.Append(msg, msg.Length);
});
}, TaskCreationOptions.LongRunning);
}

private void ReadConsoleTask()
Expand Down
Loading

0 comments on commit 83d602c

Please sign in to comment.