Skip to content

Commit

Permalink
I made a whole ton of changes and didn't commit them atomically like …
Browse files Browse the repository at this point in the history
…a smart person. was probably drinking beer. anyway some skeletal stuff works now.
  • Loading branch information
doubleyewdee committed Oct 24, 2018
1 parent 2d0a195 commit 3f44827
Show file tree
Hide file tree
Showing 12 changed files with 334 additions and 50 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
## Dev notes
- VT codes doc: https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences
- Sample for ConPTY: https://github.com/Microsoft/console/tree/master/samples/ConPTY/EchoCon
- Win32 APIs: WinBase.h, ProcessEnv.h, consoleapi.h
- Win32 APIs: WinBase.h, ProcessEnv.h, consoleapi.h
- Calculating size of a textbox: https://stackoverflow.com/questions/9264398/how-to-calculate-wpf-textblock-width-for-its-known-font-size-and-characters
85 changes: 85 additions & 0 deletions src/ConsoleBuffer/Buffer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
namespace ConsoleBuffer
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Text;

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

public short Width { get; set; }
public short Height { get; set; }

public Buffer(short width, short height)
{
this.Width = width;
this.Height = height;
this.lines.Add(new Line());
}

public void Append(byte[] bytes, int length)
{
lock (this.renderLock)
{
int currentLine = this.lines.Count - 1;
foreach (char ch in Encoding.UTF8.GetString(bytes, 0, length))
{
if (ch == '\n' || this.lines[currentLine].Length == this.Width)
{
if (currentLine == this.lines.Count - 1)
{
this.lines.Add(new Line());
++currentLine;
}

if (ch == '\n')
continue;
}

this.lines[currentLine].Append(new Character { Glyph = ch });
if (ch == ' ')
Logger.Verbose("space!");
}
}
}

/// <summary>
/// Render character-by-character onto the specified target.
/// </summary>
public void Render(IRenderTarget target)
{
lock (this.renderLock)
{
var startLine = Math.Max(0, this.lines.Count - this.Height);
for (var x = 0; x < this.Height; ++x)
{
var renderLine = startLine + x;
var line = renderLine < this.lines.Count ? this.lines[renderLine] : Line.Empty;
short y = 0;
foreach (var c in line)
{
target.RenderCharacter(c, x, y);
++y;
}
while (y < this.Width - 1)
{
target.RenderCharacter(new Character { Glyph = ' ' }, x, y);
++y;
}
}
}
}

#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string name)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
#endregion
}
}
24 changes: 24 additions & 0 deletions src/ConsoleBuffer/Character.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleBuffer
{
// XXX: Gonna end up with a lot of these and they're really freakin' big.
public struct Character
{
public struct ColorInfo
{
public byte R;
public byte G;
public byte B;
public byte A;
}

public ColorInfo Foreground { get; set; }
public ColorInfo Background { get; set; }
public char Glyph { get; set; } // XXX: char won't cut it for emoji/etc, gonna have to re-do this later!
}
}
7 changes: 7 additions & 0 deletions src/ConsoleBuffer/ConsoleBuffer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
Expand All @@ -29,6 +30,7 @@
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
Expand All @@ -41,7 +43,12 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Buffer.cs" />
<Compile Include="Character.cs" />
<Compile Include="ConsoleWrapper.cs" />
<Compile Include="IRenderTarget.cs" />
<Compile Include="Line.cs" />
<Compile Include="Logger.cs" />
<Compile Include="NativeMethods.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
Expand Down
75 changes: 38 additions & 37 deletions src/ConsoleBuffer/ConsoleWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,14 @@

public sealed class ConsoleWrapper : IDisposable, INotifyPropertyChanged
{
private string contents;
public string Contents
{
get
{
return this.contents;
}
set
{
this.contents = value;
this.OnPropertyChanged(nameof(Contents));
}
}
public Buffer Buffer { get; private set; }

public string Command { get; private set; }

private NativeMethods.COORD consoleSize = new NativeMethods.COORD { X = 25, Y = 80 };
public short Width { get { return this.width; } set { this.width = value; } }
private short width;
public short Height { get { return this.height; } set { this.height = value; } }
private short height;

/// <summary>
/// The handle from which we read data from the console.
Expand All @@ -48,30 +39,21 @@ public string Contents

public ConsoleWrapper(string command)
{
using (var sr = new StreamWriter(new FileStream(@"c:\users\wd\source\repos\wincon\fuckme.log", FileMode.Create)))
if (string.IsNullOrWhiteSpace(command))
{
sr.WriteLine($"let's start this shit");

this.Contents = string.Empty;

if (string.IsNullOrWhiteSpace(command))
{
throw new ArgumentException("No command specified.", nameof(command));
}
throw new ArgumentException("No command specified.", nameof(command));
}

this.Command = command;
sr.WriteLine($"running {command}");
this.Command = command;
this.Height = 25;
this.Width = 80;
this.Buffer = new Buffer(this.Width, this.Height);

this.CreatePTY();
sr.WriteLine($"created PTY");
this.InitializeStartupInfo();
sr.WriteLine($"initialized startup shit");
this.StartProcess();
sr.WriteLine($"started the fucking process");
this.CreatePTY();
this.InitializeStartupInfo();
this.StartProcess();

Task.Run(() => this.ReadConsoleTask());
sr.WriteLine($"fuck ME");
}
Task.Run(() => this.ReadConsoleTask());
}

private void CreatePTY()
Expand All @@ -81,7 +63,8 @@ private void CreatePTY()
if ( NativeMethods.CreatePipe(out pipeTTYin, out this.writeHandle, IntPtr.Zero, 0)
&& NativeMethods.CreatePipe(out this.readHandle, out pipeTTYout, IntPtr.Zero, 0))
{
ThrowForHResult(NativeMethods.CreatePseudoConsole(this.consoleSize, pipeTTYin, pipeTTYout, 0, out this.consoleHandle),
ThrowForHResult(NativeMethods.CreatePseudoConsole(new NativeMethods.COORD { X = this.Width, Y = this.Height },
pipeTTYin, pipeTTYout, 0, out this.consoleHandle),
"Failed to create PTY");

// It is safe to close these as they have been duped to the child console host and will be closed on that end.
Expand Down Expand Up @@ -136,7 +119,7 @@ private void ReadConsoleTask()
{
using (var ptyOutput = new FileStream(this.readHandle, FileAccess.Read))
{
var input = new byte[32];
var input = new byte[2048];

while (true)
{
Expand All @@ -145,12 +128,30 @@ private void ReadConsoleTask()
return;
}

Logger.Verbose("reading ...");
var read = ptyOutput.Read(input, 0, input.Length);
this.Contents += System.Text.Encoding.UTF8.GetString(input, 0, read);
Logger.Verbose("appending ...");
this.Buffer.Append(input, read);
Logger.Verbose("notifying ...");
this.OnPropertyChanged(nameof(this.Buffer));
Logger.Verbose("notified!");
}
}
}

private void UpdateDimensions(short newHeight, short newWidth)
{
if (newHeight <= 0) throw new ArgumentOutOfRangeException(nameof(newHeight));
if (newWidth <= 0) throw new ArgumentOutOfRangeException(nameof(newWidth));

if (this.consoleHandle != IntPtr.Zero && (newHeight != this.Height || newWidth != this.Width))
{
this.height = newHeight;
this.width = newWidth;
NativeMethods.ResizePseudoConsole(this.consoleHandle, new NativeMethods.COORD { X = this.Width, Y = this.Height });
}
}

private static void ThrowForHResult(int hr, string exceptionMessage)
{
if (hr != 0)
Expand Down
13 changes: 13 additions & 0 deletions src/ConsoleBuffer/IRenderTarget.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace ConsoleBuffer
{
public interface IRenderTarget
{
/// <summary>
/// Instructs the target to render the character 'c' at x/y coordinates.
/// </summary>
/// <param name="c">Character to render.</param>
/// <param name="x">Horizontal offset.</param>
/// <param name="y">Vertical offset.</param>
void RenderCharacter(Character c, int x, int y);
}
}
46 changes: 46 additions & 0 deletions src/ConsoleBuffer/Line.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleBuffer
{
public sealed class Line : IEnumerable<Character>
{
public static readonly Line Empty = new Line();

private readonly List<Character> chars = new List<Character>();
public int Length => this.chars.Count;

/// <summary>
/// Throw another character on to the end of the line.
/// </summary>
/// <param name="ch"></param>
public void Append(Character ch)
{
this.chars.Add(ch);
}

/// <summary>
/// Set a character value at a specified position. If the line is not long enough it is extended with blanks.
/// </summary>
/// <param name="pos">Position to set.</param>
/// <param name="ch">Character value.</param>
public void Set(int pos, Character ch)
{
throw new NotImplementedException();
}

public IEnumerator<Character> GetEnumerator()
{
return chars.GetEnumerator();
}

IEnumerator IEnumerable.GetEnumerator()
{
return chars.GetEnumerator();
}
}
}
32 changes: 32 additions & 0 deletions src/ConsoleBuffer/Logger.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
namespace ConsoleBuffer
{
using System;
using System.IO;
using System.Text;

public sealed class Logger
{
private static readonly Logger Instance = new Logger();

private readonly StreamWriter writer;

private Logger()
{
this.writer = new StreamWriter(@"C:\Users\wd\Source\Repos\wincon\wincon.log", true, Encoding.UTF8);
}

private void Write(string msg)
{
lock (this.writer)
{
this.writer.WriteLine($"{DateTimeOffset.Now}: {msg}");
this.writer.Flush();
}
}

public static void Verbose(string msg)
{
Instance.Write(msg);
}
}
}
3 changes: 3 additions & 0 deletions src/condo/App.config
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,7 @@
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
<runtime>
<ThrowUnobservedTaskExceptions enabled="true" />
</runtime>
</configuration>
Loading

0 comments on commit 3f44827

Please sign in to comment.