Add output abstraction and reorganize profile

* Moves ColorSystem from Profile to Capabilities
* Renames Tty to IsTerminal
* Adds IAnsiConsoleOutput to make output more flexible

Closes #343
Closes #359
Closes #369
This commit is contained in:
Patrik Svensson 2021-04-12 18:15:21 +02:00 committed by Phil Scott
parent bc9f610258
commit 3e2eea730b
27 changed files with 194 additions and 139 deletions

View File

@ -7,7 +7,7 @@ namespace Spectre.Console.Examples
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// No colors // No colors
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
if (AnsiConsole.Profile.ColorSystem == ColorSystem.NoColors) if (AnsiConsole.Profile.Capabilities.ColorSystem == ColorSystem.NoColors)
{ {
AnsiConsole.WriteLine("No colors are supported."); AnsiConsole.WriteLine("No colors are supported.");
return; return;

View File

@ -8,13 +8,13 @@ namespace Spectre.Console.Examples
.AddColumn(new GridColumn().NoWrap().PadRight(4)) .AddColumn(new GridColumn().NoWrap().PadRight(4))
.AddColumn() .AddColumn()
.AddRow("[b]Enrichers[/]", string.Join(", ", AnsiConsole.Profile.Enrichers)) .AddRow("[b]Enrichers[/]", string.Join(", ", AnsiConsole.Profile.Enrichers))
.AddRow("[b]Color system[/]", $"{AnsiConsole.Profile.ColorSystem}") .AddRow("[b]Color system[/]", $"{AnsiConsole.Profile.Capabilities.ColorSystem}")
.AddRow("[b]Unicode?[/]", $"{YesNo(AnsiConsole.Profile.Capabilities.Unicode)}") .AddRow("[b]Unicode?[/]", $"{YesNo(AnsiConsole.Profile.Capabilities.Unicode)}")
.AddRow("[b]Supports ansi?[/]", $"{YesNo(AnsiConsole.Profile.Capabilities.Ansi)}") .AddRow("[b]Supports ansi?[/]", $"{YesNo(AnsiConsole.Profile.Capabilities.Ansi)}")
.AddRow("[b]Supports links?[/]", $"{YesNo(AnsiConsole.Profile.Capabilities.Links)}") .AddRow("[b]Supports links?[/]", $"{YesNo(AnsiConsole.Profile.Capabilities.Links)}")
.AddRow("[b]Legacy console?[/]", $"{YesNo(AnsiConsole.Profile.Capabilities.Legacy)}") .AddRow("[b]Legacy console?[/]", $"{YesNo(AnsiConsole.Profile.Capabilities.Legacy)}")
.AddRow("[b]Interactive?[/]", $"{YesNo(AnsiConsole.Profile.Capabilities.Interactive)}") .AddRow("[b]Interactive?[/]", $"{YesNo(AnsiConsole.Profile.Capabilities.Interactive)}")
.AddRow("[b]TTY?[/]", $"{YesNo(AnsiConsole.Profile.Capabilities.Tty)}") .AddRow("[b]Terminal?[/]", $"{YesNo(AnsiConsole.Profile.Out.IsTerminal)}")
.AddRow("[b]Buffer width[/]", $"{AnsiConsole.Console.Profile.Width}") .AddRow("[b]Buffer width[/]", $"{AnsiConsole.Console.Profile.Width}")
.AddRow("[b]Buffer height[/]", $"{AnsiConsole.Console.Profile.Height}") .AddRow("[b]Buffer height[/]", $"{AnsiConsole.Console.Profile.Height}")
.AddRow("[b]Encoding[/]", $"{AnsiConsole.Console.Profile.Encoding.EncodingName}"); .AddRow("[b]Encoding[/]", $"{AnsiConsole.Console.Profile.Encoding.EncodingName}");

View File

@ -33,7 +33,7 @@ namespace Spectre.Console.Testing
{ {
Ansi = ansi, Ansi = ansi,
ColorSystem = (ColorSystemSupport)colors, ColorSystem = (ColorSystemSupport)colors,
Out = _writer, Out = new AnsiConsoleOutput(_writer),
Enrichment = new ProfileEnrichment Enrichment = new ProfileEnrichment
{ {
UseDefaultEnrichers = false, UseDefaultEnrichers = false,

View File

@ -2,13 +2,15 @@ namespace Spectre.Console.Testing
{ {
public sealed class FakeCapabilities : IReadOnlyCapabilities public sealed class FakeCapabilities : IReadOnlyCapabilities
{ {
public ColorSystem ColorSystem { get; set; } = ColorSystem.TrueColor;
public bool Ansi { get; set; } public bool Ansi { get; set; }
public bool Links { get; set; } public bool Links { get; set; }
public bool Legacy { get; set; } public bool Legacy { get; set; }
public bool Tty { get; set; } public bool IsTerminal { get; set; }
public bool Interactive { get; set; } public bool Interactive { get; set; }

View File

@ -16,7 +16,7 @@ namespace Spectre.Console.Testing
public RenderPipeline Pipeline { get; } public RenderPipeline Pipeline { get; }
public FakeConsoleInput Input { get; } public FakeConsoleInput Input { get; }
public string Output => Profile.Out.ToString(); public string Output => Profile.Out.Writer.ToString();
public IReadOnlyList<string> Lines => Output.TrimEnd('\n').Split(new char[] { '\n' }); public IReadOnlyList<string> Lines => Output.TrimEnd('\n').Split(new char[] { '\n' });
public FakeConsole( public FakeConsole(
@ -28,10 +28,10 @@ namespace Spectre.Console.Testing
ExclusivityMode = new FakeExclusivityMode(); ExclusivityMode = new FakeExclusivityMode();
Pipeline = new RenderPipeline(); Pipeline = new RenderPipeline();
Profile = new Profile(new StringWriter(), encoding ?? Encoding.UTF8); Profile = new Profile(new AnsiConsoleOutput(new StringWriter()), encoding ?? Encoding.UTF8);
Profile.Width = width; Profile.Width = width;
Profile.Height = height; Profile.Height = height;
Profile.ColorSystem = colorSystem; Profile.Capabilities.ColorSystem = colorSystem;
Profile.Capabilities.Ansi = supportsAnsi; Profile.Capabilities.Ansi = supportsAnsi;
Profile.Capabilities.Legacy = legacyConsole; Profile.Capabilities.Legacy = legacyConsole;
Profile.Capabilities.Interactive = interactive; Profile.Capabilities.Interactive = interactive;
@ -41,7 +41,7 @@ namespace Spectre.Console.Testing
public void Dispose() public void Dispose()
{ {
Profile.Out.Dispose(); Profile.Out.Writer.Dispose();
} }
public void Clear(bool home) public void Clear(bool home)
@ -52,7 +52,7 @@ namespace Spectre.Console.Testing
{ {
foreach (var segment in renderable.GetSegments(this)) foreach (var segment in renderable.GetSegments(this))
{ {
Profile.Out.Write(segment.Text); Profile.Out.Writer.Write(segment.Text);
} }
} }

View File

@ -19,11 +19,11 @@ namespace Spectre.Console.Tests.Unit
var console = AnsiConsole.Create(new AnsiConsoleSettings var console = AnsiConsole.Create(new AnsiConsoleSettings
{ {
ColorSystem = requested, ColorSystem = requested,
Out = new StringWriter(), Out = new AnsiConsoleOutput(new StringWriter()),
}); });
// Then // Then
console.Profile.ColorSystem.ShouldBe(expected); console.Profile.Capabilities.ColorSystem.ShouldBe(expected);
} }
public sealed class TrueColor public sealed class TrueColor

View File

@ -20,7 +20,7 @@ namespace Spectre.Console.Tests.Unit
public string Render() public string Render()
{ {
var console = new FakeConsole(); var console = new FakeConsole();
var context = new RenderContext(console.Profile.ColorSystem, console.Profile.Capabilities); var context = new RenderContext(console.Profile.Capabilities);
console.Write(Column.Render(context, Task, TimeSpan.Zero)); console.Write(Column.Render(context, Task, TimeSpan.Zero));
return console.Output; return console.Output;
} }

View File

@ -130,7 +130,6 @@ namespace Spectre.Console.Tests.Unit
} }
[Theory] [Theory]
[InlineData(0, "Hello World Hello World Hello World Hello World Hello World", "")]
[InlineData(1, "Hello World Hello World Hello World Hello World Hello World", "─")] [InlineData(1, "Hello World Hello World Hello World Hello World Hello World", "─")]
[InlineData(2, "Hello World Hello World Hello World Hello World Hello World", "──")] [InlineData(2, "Hello World Hello World Hello World Hello World Hello World", "──")]
[InlineData(3, "Hello World Hello World Hello World Hello World Hello World", "───")] [InlineData(3, "Hello World Hello World Hello World Hello World Hello World", "───")]

View File

@ -15,7 +15,7 @@ namespace Spectre.Console.Tests.Unit
var text = new Text("Foo Bar Baz\nQux\nLol mobile"); var text = new Text("Foo Bar Baz\nQux\nLol mobile");
// When // When
var result = ((IRenderable)text).Measure(new RenderContext(ColorSystem.TrueColor, caps), 80); var result = ((IRenderable)text).Measure(new RenderContext(caps), 80);
// Then // Then
result.Min.ShouldBe(6); result.Min.ShouldBe(6);
@ -29,7 +29,7 @@ namespace Spectre.Console.Tests.Unit
var text = new Text("Foo Bar Baz\nQux\nLol mobile"); var text = new Text("Foo Bar Baz\nQux\nLol mobile");
// When // When
var result = ((IRenderable)text).Measure(new RenderContext(ColorSystem.TrueColor, caps), 80); var result = ((IRenderable)text).Measure(new RenderContext(caps), 80);
// Then // Then
result.Max.ShouldBe(11); result.Max.ShouldBe(11);

View File

@ -15,7 +15,7 @@ namespace Spectre.Console
{ {
Ansi = AnsiSupport.Detect, Ansi = AnsiSupport.Detect,
ColorSystem = ColorSystemSupport.Detect, ColorSystem = ColorSystemSupport.Detect,
Out = System.Console.Out, Out = new AnsiConsoleOutput(System.Console.Out),
}); });
Created = true; Created = true;

View File

@ -22,13 +22,18 @@ namespace Spectre.Console
throw new ArgumentNullException(nameof(settings)); throw new ArgumentNullException(nameof(settings));
} }
var buffer = settings.Out ?? System.Console.Out; var output = settings.Out ?? new AnsiConsoleOutput(System.Console.Out);
if (output.Writer == null)
{
throw new InvalidOperationException("Output writer was null");
}
// Detect if the terminal support ANSI or not // Detect if the terminal support ANSI or not
var (supportsAnsi, legacyConsole) = DetectAnsi(settings, buffer); var (supportsAnsi, legacyConsole) = DetectAnsi(settings, output.Writer);
// Use console encoding or fall back to provided encoding // Use console encoding or fall back to provided encoding
var encoding = buffer.IsStandardOut() || buffer.IsStandardError() ? System.Console.OutputEncoding : buffer.Encoding; var encoding = output.Writer.IsStandardOut() || output.Writer.IsStandardError()
? System.Console.OutputEncoding : output.Writer.Encoding;
// Get the color system // Get the color system
var colorSystem = settings.ColorSystem == ColorSystemSupport.Detect var colorSystem = settings.ColorSystem == ColorSystemSupport.Detect
@ -42,11 +47,9 @@ namespace Spectre.Console
interactive = Environment.UserInteractive; interactive = Environment.UserInteractive;
} }
var profile = new Profile(buffer, encoding) var profile = new Profile(output, encoding);
{
ColorSystem = colorSystem,
};
profile.Capabilities.ColorSystem = colorSystem;
profile.Capabilities.Ansi = supportsAnsi; profile.Capabilities.Ansi = supportsAnsi;
profile.Capabilities.Links = supportsAnsi && !legacyConsole; profile.Capabilities.Links = supportsAnsi && !legacyConsole;
profile.Capabilities.Legacy = legacyConsole; profile.Capabilities.Legacy = legacyConsole;

View File

@ -0,0 +1,58 @@
using System;
using System.IO;
using System.Text;
namespace Spectre.Console
{
/// <summary>
/// Represents console output.
/// </summary>
public sealed class AnsiConsoleOutput : IAnsiConsoleOutput
{
/// <inheritdoc/>
public TextWriter Writer { get; }
/// <inheritdoc/>
public bool IsTerminal
{
get
{
if (Writer.IsStandardOut())
{
return !System.Console.IsOutputRedirected;
}
if (Writer.IsStandardError())
{
return !System.Console.IsErrorRedirected;
}
return false;
}
}
/// <inheritdoc/>
public int Width => ConsoleHelper.GetSafeWidth(Constants.DefaultTerminalWidth);
/// <inheritdoc/>
public int Height => ConsoleHelper.GetSafeHeight(Constants.DefaultTerminalWidth);
/// <summary>
/// Initializes a new instance of the <see cref="AnsiConsoleOutput"/> class.
/// </summary>
/// <param name="writer">The output writer.</param>
public AnsiConsoleOutput(TextWriter writer)
{
Writer = writer ?? throw new ArgumentNullException(nameof(writer));
}
/// <inheritdoc/>
public void SetEncoding(Encoding encoding)
{
if (Writer.IsStandardOut() || Writer.IsStandardError())
{
System.Console.OutputEncoding = encoding;
}
}
}
}

View File

@ -1,5 +1,4 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
namespace Spectre.Console namespace Spectre.Console
{ {
@ -22,7 +21,7 @@ namespace Spectre.Console
/// <summary> /// <summary>
/// Gets or sets the out buffer. /// Gets or sets the out buffer.
/// </summary> /// </summary>
public TextWriter? Out { get; set; } public IAnsiConsoleOutput? Out { get; set; }
/// <summary> /// <summary>
/// Gets or sets a value indicating whether or not the /// Gets or sets a value indicating whether or not the

View File

@ -7,7 +7,12 @@ namespace Spectre.Console
/// </summary> /// </summary>
public sealed class Capabilities : IReadOnlyCapabilities public sealed class Capabilities : IReadOnlyCapabilities
{ {
private readonly Profile _profile; private readonly IAnsiConsoleOutput _out;
/// <summary>
/// Gets or sets the color system.
/// </summary>
public ColorSystem ColorSystem { get; set; }
/// <summary> /// <summary>
/// Gets or sets a value indicating whether or not /// Gets or sets a value indicating whether or not
@ -33,26 +38,10 @@ namespace Spectre.Console
/// <summary> /// <summary>
/// Gets a value indicating whether or not /// Gets a value indicating whether or not
/// console output has been redirected. /// the output is a terminal.
/// </summary> /// </summary>
public bool Tty [Obsolete("Use Profile.Out.IsTerminal instead")]
{ public bool IsTerminal => _out.IsTerminal;
get
{
if (_profile.Out.IsStandardOut())
{
return System.Console.IsOutputRedirected;
}
if (_profile.Out.IsStandardError())
{
return System.Console.IsErrorRedirected;
}
// Not stdout, so must be a TTY.
return true;
}
}
/// <summary> /// <summary>
/// Gets or sets a value indicating whether /// Gets or sets a value indicating whether
@ -67,11 +56,12 @@ namespace Spectre.Console
public bool Unicode { get; set; } public bool Unicode { get; set; }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Capabilities"/> class. /// Initializes a new instance of the
/// <see cref="Capabilities"/> class.
/// </summary> /// </summary>
internal Capabilities(Profile profile) internal Capabilities(IAnsiConsoleOutput @out)
{ {
_profile = profile ?? throw new ArgumentNullException(nameof(profile)); _out = @out ?? throw new ArgumentNullException(nameof(@out));
} }
} }
} }

View File

@ -27,7 +27,7 @@ namespace Spectre.Console
throw new ArgumentNullException(nameof(renderable)); throw new ArgumentNullException(nameof(renderable));
} }
var context = new RenderContext(console.Profile.ColorSystem, console.Profile.Capabilities); var context = new RenderContext(console.Profile.Capabilities);
var renderables = console.Pipeline.Process(context, new[] { renderable }); var renderables = console.Pipeline.Process(context, new[] { renderable });
return GetSegments(console, context, renderables); return GetSegments(console, context, renderables);

View File

@ -0,0 +1,37 @@
using System.IO;
using System.Text;
namespace Spectre.Console
{
/// <summary>
/// Represents console output.
/// </summary>
public interface IAnsiConsoleOutput
{
/// <summary>
/// Gets the <see cref="TextWriter"/> used to write to the output.
/// </summary>
TextWriter Writer { get; }
/// <summary>
/// Gets a value indicating whether or not the output is a terminal.
/// </summary>
bool IsTerminal { get; }
/// <summary>
/// Gets the output width.
/// </summary>
int Width { get; }
/// <summary>
/// Gets the output height.
/// </summary>
int Height { get; }
/// <summary>
/// Sets the output encoding.
/// </summary>
/// <param name="encoding">The encoding.</param>
void SetEncoding(Encoding encoding);
}
}

View File

@ -1,3 +1,5 @@
using System;
namespace Spectre.Console namespace Spectre.Console
{ {
/// <summary> /// <summary>
@ -5,6 +7,11 @@ namespace Spectre.Console
/// </summary> /// </summary>
public interface IReadOnlyCapabilities public interface IReadOnlyCapabilities
{ {
/// <summary>
/// Gets the color system.
/// </summary>
ColorSystem ColorSystem { get; }
/// <summary> /// <summary>
/// Gets a value indicating whether or not /// Gets a value indicating whether or not
/// the console supports Ansi. /// the console supports Ansi.
@ -31,7 +38,8 @@ namespace Spectre.Console
/// Gets a value indicating whether or not /// Gets a value indicating whether or not
/// console output has been redirected. /// console output has been redirected.
/// </summary> /// </summary>
bool Tty { get; } [Obsolete("Use Profile.Out.IsTerminal instead")]
bool IsTerminal { get; }
/// <summary> /// <summary>
/// Gets a value indicating whether /// Gets a value indicating whether

View File

@ -29,7 +29,7 @@ namespace Spectre.Console
{ {
codes = codes.Concat( codes = codes.Concat(
AnsiColorBuilder.GetAnsiCodes( AnsiColorBuilder.GetAnsiCodes(
_profile.ColorSystem, _profile.Capabilities.ColorSystem,
style.Foreground, style.Foreground,
true)); true));
} }
@ -39,7 +39,7 @@ namespace Spectre.Console
{ {
codes = codes.Concat( codes = codes.Concat(
AnsiColorBuilder.GetAnsiCodes( AnsiColorBuilder.GetAnsiCodes(
_profile.ColorSystem, _profile.Capabilities.ColorSystem,
style.Background, style.Background,
false)); false));
} }

View File

@ -59,8 +59,8 @@ namespace Spectre.Console
if (builder.Length > 0) if (builder.Length > 0)
{ {
_console.Profile.Out.Write(builder.ToString()); _console.Profile.Out.Writer.Write(builder.ToString());
_console.Profile.Out.Flush(); _console.Profile.Out.Writer.Flush();
} }
} }
} }

View File

@ -44,7 +44,7 @@ namespace Spectre.Console
SetStyle(segment.Style); SetStyle(segment.Style);
} }
_console.Profile.Out.Write(segment.Text.NormalizeNewLines(native: true)); _console.Profile.Out.Writer.Write(segment.Text.NormalizeNewLines(native: true));
} }
} }
@ -55,13 +55,13 @@ namespace Spectre.Console
System.Console.ResetColor(); System.Console.ResetColor();
var background = Color.ToConsoleColor(style.Background); var background = Color.ToConsoleColor(style.Background);
if (_console.Profile.ColorSystem != ColorSystem.NoColors && (int)background != -1) if (_console.Profile.Capabilities.ColorSystem != ColorSystem.NoColors && (int)background != -1)
{ {
System.Console.BackgroundColor = background; System.Console.BackgroundColor = background;
} }
var foreground = Color.ToConsoleColor(style.Foreground); var foreground = Color.ToConsoleColor(style.Foreground);
if (_console.Profile.ColorSystem != ColorSystem.NoColors && (int)foreground != -1) if (_console.Profile.Capabilities.ColorSystem != ColorSystem.NoColors && (int)foreground != -1)
{ {
System.Console.ForegroundColor = foreground; System.Console.ForegroundColor = foreground;
} }

View File

@ -13,11 +13,6 @@ namespace Spectre.Console
public ConsoleKeyInfo ReadKey(bool intercept) public ConsoleKeyInfo ReadKey(bool intercept)
{ {
if (_profile.Capabilities.Tty)
{
throw new InvalidOperationException("Cannot read input from a TTY console.");
}
if (!_profile.Capabilities.Interactive) if (!_profile.Capabilities.Interactive)
{ {
throw new InvalidOperationException("Failed to read input in non-interactive mode."); throw new InvalidOperationException("Failed to read input in non-interactive mode.");

View File

@ -0,0 +1,19 @@
namespace Spectre.Console.Internal
{
internal sealed class EncoderCapabilities : IReadOnlyCapabilities
{
public ColorSystem ColorSystem { get; }
public bool Ansi => false;
public bool Links => false;
public bool Legacy => false;
public bool IsTerminal => false;
public bool Interactive => false;
public bool Unicode => true;
public EncoderCapabilities(ColorSystem colors)
{
ColorSystem = colors;
}
}
}

View File

@ -9,7 +9,7 @@ namespace Spectre.Console.Internal
{ {
public string Encode(IAnsiConsole console, IEnumerable<IRenderable> renderables) public string Encode(IAnsiConsole console, IEnumerable<IRenderable> renderables)
{ {
var context = new RenderContext(ColorSystem.TrueColor, EncoderCapabilities.Default); var context = new RenderContext(new EncoderCapabilities(ColorSystem.TrueColor));
var builder = new StringBuilder(); var builder = new StringBuilder();
builder.Append("<pre style=\"font-size:90%;font-family:consolas,'Courier New',monospace\">\n"); builder.Append("<pre style=\"font-size:90%;font-family:consolas,'Courier New',monospace\">\n");

View File

@ -4,23 +4,11 @@ using Spectre.Console.Rendering;
namespace Spectre.Console.Internal namespace Spectre.Console.Internal
{ {
internal sealed class EncoderCapabilities : IReadOnlyCapabilities
{
public bool Ansi => false;
public bool Links => false;
public bool Legacy => false;
public bool Tty => false;
public bool Interactive => false;
public bool Unicode => true;
public static EncoderCapabilities Default { get; } = new EncoderCapabilities();
}
internal sealed class TextEncoder : IAnsiConsoleEncoder internal sealed class TextEncoder : IAnsiConsoleEncoder
{ {
public string Encode(IAnsiConsole console, IEnumerable<IRenderable> renderables) public string Encode(IAnsiConsole console, IEnumerable<IRenderable> renderables)
{ {
var context = new RenderContext(ColorSystem.TrueColor, EncoderCapabilities.Default); var context = new RenderContext(new EncoderCapabilities(ColorSystem.TrueColor));
var builder = new StringBuilder(); var builder = new StringBuilder();
foreach (var renderable in renderables) foreach (var renderable in renderables)

View File

@ -1,6 +1,5 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Text; using System.Text;
namespace Spectre.Console namespace Spectre.Console
@ -13,7 +12,7 @@ namespace Spectre.Console
private readonly HashSet<string> _enrichers; private readonly HashSet<string> _enrichers;
private static readonly string[] _defaultEnricher = new[] { "Default" }; private static readonly string[] _defaultEnricher = new[] { "Default" };
private TextWriter _out; private IAnsiConsoleOutput _out;
private Encoding _encoding; private Encoding _encoding;
private Capabilities _capabilities; private Capabilities _capabilities;
private int? _width; private int? _width;
@ -38,15 +37,15 @@ namespace Spectre.Console
/// <summary> /// <summary>
/// Gets or sets the out buffer. /// Gets or sets the out buffer.
/// </summary> /// </summary>
public TextWriter Out public IAnsiConsoleOutput Out
{ {
get => _out; get => _out;
set set
{ {
_out = value ?? throw new InvalidOperationException("Output buffer cannot be null"); _out = value ?? throw new InvalidOperationException("Output buffer cannot be null");
// Reset the width and height if not a TTY. // Reset the width and height if this is a terminal.
if (!Capabilities.Tty) if (value.IsTerminal)
{ {
_width = null; _width = null;
_height = null; _height = null;
@ -67,12 +66,7 @@ namespace Spectre.Console
throw new InvalidOperationException("Encoding cannot be null"); throw new InvalidOperationException("Encoding cannot be null");
} }
// Need to update the output encoding for stdout? _out.SetEncoding(value);
if (_out.IsStandardOut() || _out.IsStandardError())
{
System.Console.OutputEncoding = value;
}
_encoding = value; _encoding = value;
} }
} }
@ -82,10 +76,10 @@ namespace Spectre.Console
/// </summary> /// </summary>
public int Width public int Width
{ {
get => GetWidth(); get => _width ?? _out.Width;
set set
{ {
if (_width <= 0) if (value <= 0)
{ {
throw new InvalidOperationException("Console width must be greater than zero"); throw new InvalidOperationException("Console width must be greater than zero");
} }
@ -99,10 +93,10 @@ namespace Spectre.Console
/// </summary> /// </summary>
public int Height public int Height
{ {
get => GetHeight(); get => _height ?? _out.Height;
set set
{ {
if (_height <= 0) if (value <= 0)
{ {
throw new InvalidOperationException("Console height must be greater than zero"); throw new InvalidOperationException("Console height must be greater than zero");
} }
@ -111,11 +105,6 @@ namespace Spectre.Console
} }
} }
/// <summary>
/// Gets or sets the color system.
/// </summary>
public ColorSystem ColorSystem { get; set; }
/// <summary> /// <summary>
/// Gets or sets the capabilities of the profile. /// Gets or sets the capabilities of the profile.
/// </summary> /// </summary>
@ -133,12 +122,12 @@ namespace Spectre.Console
/// </summary> /// </summary>
/// <param name="out">The output buffer.</param> /// <param name="out">The output buffer.</param>
/// <param name="encoding">The output encoding.</param> /// <param name="encoding">The output encoding.</param>
public Profile(TextWriter @out, Encoding encoding) public Profile(IAnsiConsoleOutput @out, Encoding encoding)
{ {
_enrichers = new HashSet<string>(StringComparer.OrdinalIgnoreCase); _enrichers = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
_out = @out ?? throw new ArgumentNullException(nameof(@out)); _out = @out ?? throw new ArgumentNullException(nameof(@out));
_encoding = encoding ?? throw new ArgumentNullException(nameof(encoding)); _encoding = encoding ?? throw new ArgumentNullException(nameof(encoding));
_capabilities = new Capabilities(this); _capabilities = new Capabilities(_out);
} }
/// <summary> /// <summary>
@ -149,7 +138,7 @@ namespace Spectre.Console
/// <returns><c>true</c> if the color system is supported, otherwise <c>false</c>.</returns> /// <returns><c>true</c> if the color system is supported, otherwise <c>false</c>.</returns>
public bool Supports(ColorSystem colorSystem) public bool Supports(ColorSystem colorSystem)
{ {
return (int)colorSystem <= (int)ColorSystem; return (int)colorSystem <= (int)Capabilities.ColorSystem;
} }
internal void AddEnricher(string name) internal void AddEnricher(string name)
@ -161,35 +150,5 @@ namespace Spectre.Console
_enrichers.Add(name); _enrichers.Add(name);
} }
private int GetWidth()
{
if (_width != null)
{
return _width.Value;
}
if (!Capabilities.Tty)
{
return ConsoleHelper.GetSafeWidth(Constants.DefaultTerminalWidth);
}
return Constants.DefaultTerminalWidth;
}
private int GetHeight()
{
if (_height != null)
{
return _height.Value;
}
if (!Capabilities.Tty)
{
return ConsoleHelper.GetSafeHeight(Constants.DefaultTerminalHeight);
}
return Constants.DefaultTerminalHeight;
}
} }
} }

View File

@ -12,7 +12,7 @@ namespace Spectre.Console.Rendering
/// <summary> /// <summary>
/// Gets the current color system. /// Gets the current color system.
/// </summary> /// </summary>
public ColorSystem ColorSystem { get; } public ColorSystem ColorSystem => _capabilities.ColorSystem;
/// <summary> /// <summary>
/// Gets a value indicating whether or not unicode is supported. /// Gets a value indicating whether or not unicode is supported.
@ -33,19 +33,17 @@ namespace Spectre.Console.Rendering
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RenderContext"/> class. /// Initializes a new instance of the <see cref="RenderContext"/> class.
/// </summary> /// </summary>
/// <param name="colorSystem">The color system.</param>
/// <param name="capabilities">The capabilities.</param> /// <param name="capabilities">The capabilities.</param>
/// <param name="justification">The justification.</param> /// <param name="justification">The justification.</param>
public RenderContext(ColorSystem colorSystem, IReadOnlyCapabilities capabilities, Justify? justification = null) public RenderContext(IReadOnlyCapabilities capabilities, Justify? justification = null)
: this(colorSystem, capabilities, justification, false) : this(capabilities, justification, false)
{ {
} }
private RenderContext(ColorSystem colorSystem, IReadOnlyCapabilities capabilities, Justify? justification = null, bool singleLine = false) private RenderContext(IReadOnlyCapabilities capabilities, Justify? justification = null, bool singleLine = false)
{ {
_capabilities = capabilities ?? throw new ArgumentNullException(nameof(capabilities)); _capabilities = capabilities ?? throw new ArgumentNullException(nameof(capabilities));
ColorSystem = colorSystem;
Justification = justification; Justification = justification;
SingleLine = singleLine; SingleLine = singleLine;
} }
@ -57,7 +55,7 @@ namespace Spectre.Console.Rendering
/// <returns>A new <see cref="RenderContext"/> instance.</returns> /// <returns>A new <see cref="RenderContext"/> instance.</returns>
public RenderContext WithJustification(Justify? justification) public RenderContext WithJustification(Justify? justification)
{ {
return new RenderContext(ColorSystem, _capabilities, justification, SingleLine); return new RenderContext(_capabilities, justification, SingleLine);
} }
/// <summary> /// <summary>
@ -72,7 +70,7 @@ namespace Spectre.Console.Rendering
/// <returns>A new <see cref="RenderContext"/> instance.</returns> /// <returns>A new <see cref="RenderContext"/> instance.</returns>
internal RenderContext WithSingleLine() internal RenderContext WithSingleLine()
{ {
return new RenderContext(ColorSystem, _capabilities, Justification, true); return new RenderContext(_capabilities, Justification, true);
} }
} }
} }

View File

@ -62,7 +62,7 @@ namespace Spectre.Console
_stopwatch.Start(); _stopwatch.Start();
} }
var renderContext = new RenderContext(_console.Profile.ColorSystem, _console.Profile.Capabilities); var renderContext = new RenderContext(_console.Profile.Capabilities);
var delta = _stopwatch.Elapsed - _lastUpdate; var delta = _stopwatch.Elapsed - _lastUpdate;
_lastUpdate = _stopwatch.Elapsed; _lastUpdate = _stopwatch.Elapsed;