Dependencies/Pixie/Pixie.Terminal/Devices/TextWriterTerminal.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace WasmBox.Pixie.Terminal.Devices {
/// <summary>
/// A terminal that writes to a text writer.
/// </summary>
public class TextWriterTerminal : OutputTerminalBase {
/// <summary>
/// Creates a text writer terminal from a text writer
/// and a terminal width.
/// </summary>
/// <param name="writer">A text writer to send output to.</param>
/// <param name="width">The width of the output document.</param>
public TextWriterTerminal(
TextWriter writer,
int width)
: this(writer, width, NoStyleManager.Instance) { }
/// <summary>
/// Creates a text writer terminal from a text writer,
/// a terminal width and a style manager.
/// </summary>
/// <param name="writer">A text writer to send output to.</param>
/// <param name="width">The width of the output document.</param>
/// <param name="styleManager">A style manager for the output document.</param>
public TextWriterTerminal(
TextWriter writer,
int width,
StyleManager styleManager)
: this(writer, width, styleManager, writer.Encoding) { }
/// <summary>
/// Creates a text writer terminal from a text writer,
/// a terminal width and a text encoding.
/// </summary>
/// <param name="writer">A text writer to send output to.</param>
/// <param name="width">The width of the output document.</param>
/// <param name="renderableEncoding">
/// The encoding that is used for determining which strings are renderable and which are not.
/// </param>
public TextWriterTerminal(
TextWriter writer,
int width,
Encoding renderableEncoding)
: this(writer, width, NoStyleManager.Instance, renderableEncoding) { }
/// <summary>
/// Creates a text writer terminal from a text writer,
/// a terminal width, a style manager and a text encoding.
/// </summary>
/// <param name="writer">A text writer to send output to.</param>
/// <param name="width">The width of the output document.</param>
/// <param name="styleManager">A style manager for the output document.</param>
/// <param name="renderableEncoding">
/// The encoding that is used for determining which strings are renderable and which are not.
/// </param>
public TextWriterTerminal(
TextWriter writer,
int width,
StyleManager styleManager,
Encoding renderableEncoding) {
this.Writer = writer;
this.termWidth = width;
this.styleManager = styleManager;
this.renderableTestEncoding = (Encoding)renderableEncoding.Clone();
this.renderableTestEncoding.EncoderFallback = new RenderableEncoderFallback();
}
/// <summary>
/// Gets the text writer to which output is sent by this terminal.
/// </summary>
/// <returns>A text writer.</returns>
public TextWriter Writer { get; private set; }
private int termWidth;
private Encoding renderableTestEncoding;
/// <inheritdoc/>
public override int Width => termWidth;
private StyleManager styleManager;
/// <inheritdoc/>
public override StyleManager Style => styleManager;
/// <inheritdoc/>
public override void Write(string text) {
EndSeparator();
Writer.Write(text);
}
/// <inheritdoc/>
protected override void WriteLineImpl() {
Writer.WriteLine();
}
/// <inheritdoc/>
public override void Write(char character) {
EndSeparator();
Writer.Write(character);
}
/// <inheritdoc/>
public override bool CanRender(string text) {
var fallback = (RenderableEncoderFallback)renderableTestEncoding.EncoderFallback;
fallback.FoundUnencodable = false;
renderableTestEncoding.GetBytes(text);
return !fallback.FoundUnencodable;
}
/// <summary>
/// Creates a text writer terminal from the given console stream and
/// a flag that tells if said stream's output is being redirected.
/// <param name="writer">
/// A writer to write output to.
/// </param>
/// </summary>
/// <param name="isRedirected">
/// Tells if the writer's output is being redirected.
/// </param>
/// <param name="styleManagerOrNull">
/// The style manager to use. Pass <c>null</c> to automatically
/// pick a style manager based on the terminal.
/// </param>
/// <param name="terminalWidthOrNull">
/// The size of the terminal to use. Pass <c>null</c> to automatically
/// pick the width based on the terminal.
/// </param>
/// <returns>A text writer terminal.</returns>
// private static TextWriterTerminal FromConsoleStream(
// TextWriter writer,
// bool isRedirected,
// StyleManager styleManagerOrNull,
// Nullable<int> terminalWidthOrNull)
// {
// if (isRedirected)
// {
// // Don't style redirected text.
// return new TextWriterTerminal(
// writer,
// terminalWidthOrNull.HasValue
// ? terminalWidthOrNull.Value
// : DefaultTerminalWidth,
// styleManagerOrNull ?? NoStyleManager.Instance,
// GetSafeEncoding(writer));
// }
// var termIdentifier = EnvironmentTerminalIdentifier;
// if (termIdentifier != null && IsAnsiTerminalIdentifier(termIdentifier.ToLowerInvariant()))
// {
// // Only use ANSI control sequences if the terminal
// // appears receptive.
// return new TextWriterTerminal(
// writer,
// terminalWidthOrNull.HasValue
// ? terminalWidthOrNull.Value
// : GetTerminalWidth(),
// styleManagerOrNull ?? new AnsiStyleManager(writer));
// }
// else
// {
// // As a fallback, use 'System.Console' for styles.
// // Also, don't trust the writer's encoding on Windows;
// // restrict ourselves to ASCII.
// return new TextWriterTerminal(
// writer,
// terminalWidthOrNull.HasValue
// ? terminalWidthOrNull.Value
// : GetTerminalWidth(),
// styleManagerOrNull ?? new ConsoleStyleManager(),
// GetSafeEncoding(writer));
// }
// }
/// <summary>
/// Creates a text writer terminal from the console output stream,
/// a style manager and the width of the output buffer.
/// </summary>
/// <param name="styleManager">
/// A style manager to style the output with.
/// </param>
/// <param name="width">
/// The width of the output buffer.
/// </param>
/// <returns>A text writer terminal.</returns>
// public static TextWriterTerminal FromOutputStream(
// StyleManager styleManager,
// int width)
// {
// return FromConsoleStream(
// Console.Out,
// Console.IsOutputRedirected,
// styleManager,
// new Nullable<int>(width));
// }
/// <summary>
/// Creates a text writer terminal from the console output stream
/// and a style manager.
/// </summary>
/// <param name="styleManager">
/// A style manager to style the output with.
/// </param>
/// <returns>A text writer terminal.</returns>
// public static TextWriterTerminal FromOutputStream(
// StyleManager styleManager)
// {
// return FromConsoleStream(
// Console.Out,
// Console.IsOutputRedirected,
// styleManager,
// default(Nullable<int>));
// }
/// <summary>
/// Creates a text writer terminal from the console output stream.
/// </summary>
/// <returns>A text writer terminal.</returns>
// public static TextWriterTerminal FromOutputStream()
// {
// return FromConsoleStream(
// Console.Out,
// Console.IsOutputRedirected,
// null,
// default(Nullable<int>));
// }
/// <summary>
/// Creates a text writer terminal from the console error stream,
/// a style manager and the width of the output buffer.
/// </summary>
/// <param name="styleManager">
/// A style manager to style the output with.
/// </param>
/// <param name="width">
/// The width of the output buffer.
/// </param>
/// <returns>A text writer terminal.</returns>
// public static TextWriterTerminal FromErrorStream(
// StyleManager styleManager,
// int width)
// {
// return FromConsoleStream(
// Console.Error,
// Console.IsErrorRedirected,
// styleManager,
// new Nullable<int>(width));
// }
/// <summary>
/// Creates a text writer terminal from the console error stream
/// and a style manager.
/// </summary>
/// <param name="styleManager">
/// A style manager to style the output with.
/// </param>
/// <returns>A text writer terminal.</returns>
// public static TextWriterTerminal FromErrorStream(
// StyleManager styleManager)
// {
// return FromConsoleStream(
// Console.Error,
// Console.IsErrorRedirected,
// styleManager,
// default(Nullable<int>));
// }
/// <summary>
/// Creates a text writer terminal from the console error stream.
/// </summary>
/// <returns>A text writer terminal.</returns>
// public static TextWriterTerminal FromErrorStream()
// {
// return FromConsoleStream(
// Console.Error,
// Console.IsErrorRedirected,
// null,
// default(Nullable<int>));
// }
/// <summary>
/// Gets the environment's terminal identifier, if any.
/// </summary>
/// <returns>A terminal identifier.</returns>
// public static string EnvironmentTerminalIdentifier =>
// Environment.GetEnvironmentVariable("TERM");
// private static bool IsAnsiTerminalIdentifier(string identifier)
// {
// return identifier.StartsWith("vt")
// || identifier.StartsWith("xterm")
// || identifier == "linux";
// }
// private static Encoding GetSafeEncoding(TextWriter writer)
// {
// return WindowsIsOS() ? Encoding.ASCII : writer.Encoding;
// }
// private static bool WindowsIsOS()
// {
// var platformId = Environment.OSVersion.Platform;
// switch (platformId)
// {
// case PlatformID.Win32NT:
// case PlatformID.Win32S:
// case PlatformID.Win32Windows:
// case PlatformID.WinCE:
// case PlatformID.Xbox:
// return true;
// default:
// return false;
// }
// }
// private const int DefaultTerminalWidth = 80;
// private static int GetTerminalWidth()
// {
// int result = 0;
// try
// {
// result = Console.BufferWidth;
// }
// catch (Exception)
// {
// // Console.BufferWidth can throw when using the
// // .NET framework on Cygwin. We'll just ignore
// // the error and pick the default size.
// }
// return result <= 0
// ? DefaultTerminalWidth
// : result;
// }
}
internal sealed class RenderableEncoderFallback : EncoderFallback {
public override int MaxCharCount { get { return 0; } }
public override EncoderFallbackBuffer CreateFallbackBuffer() {
return new RenderableEncoderFallbackBuffer(this);
}
/// <summary>
/// Gets or sets a Boolean that tells if any unencodable
/// characters were found.
/// </summary>
/// <returns>
/// <c>true</c> if any unencodable characters were found; otherwise, <c>false</c>.
/// </returns>
public bool FoundUnencodable { get; set; }
}
internal sealed class RenderableEncoderFallbackBuffer : EncoderFallbackBuffer {
public RenderableEncoderFallbackBuffer(RenderableEncoderFallback owner) {
this.owner = owner;
}
private RenderableEncoderFallback owner;
public override int Remaining { get { return 0; } }
public override bool Fallback(char unknownChar, int index) {
owner.FoundUnencodable = true;
return true;
}
public override bool Fallback(char charUnknownHigh, char charUnknownLow, int index) {
return false;
}
public override char GetNextChar() {
return default(char);
}
public override bool MovePrevious() {
return false;
}
public override void Reset() {
}
}
}