From 3e2eea730bf0f6fe4a5e336faa312b526d351079 Mon Sep 17 00:00:00 2001 From: Patrik Svensson Date: Mon, 12 Apr 2021 18:15:21 +0200 Subject: [PATCH] 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 --- examples/Console/Colors/Program.cs | 2 +- examples/Console/Info/Program.cs | 4 +- .../Fakes/FakeAnsiConsole.cs | 2 +- .../Fakes/FakeCapabilities.cs | 4 +- .../Fakes/FakeConsole.cs | 10 +-- .../Unit/AnsiConsoleTests.Colors.cs | 4 +- .../Unit/Progress/ProgressColumnFixture.cs | 2 +- src/Spectre.Console.Tests/Unit/RuleTests.cs | 1 - src/Spectre.Console.Tests/Unit/TextTests.cs | 4 +- src/Spectre.Console/AnsiConsole.cs | 2 +- src/Spectre.Console/AnsiConsoleFactory.cs | 17 +++-- src/Spectre.Console/AnsiConsoleOutput.cs | 58 +++++++++++++++++ src/Spectre.Console/AnsiConsoleSettings.cs | 3 +- src/Spectre.Console/Capabilities.cs | 36 ++++------ .../Extensions/RenderableExtensions.cs | 2 +- src/Spectre.Console/IAnsiConsoleOutput.cs | 37 +++++++++++ src/Spectre.Console/IReadOnlyCapabilities.cs | 10 ++- .../Internal/Backends/Ansi/AnsiBuilder.cs | 4 +- .../Backends/Ansi/AnsiConsoleBackend.cs | 4 +- .../Backends/Legacy/LegacyConsoleBackend.cs | 6 +- src/Spectre.Console/Internal/DefaultInput.cs | 5 -- .../Text/Encoding/EncoderCapabilities.cs | 19 ++++++ .../Internal/Text/Encoding/HtmlEncoder.cs | 2 +- .../Internal/Text/Encoding/TextEncoder.cs | 14 +--- src/Spectre.Console/Profile.cs | 65 ++++--------------- .../Rendering/RenderContext.cs | 14 ++-- .../Renderers/DefaultProgressRenderer.cs | 2 +- 27 files changed, 194 insertions(+), 139 deletions(-) create mode 100644 src/Spectre.Console/AnsiConsoleOutput.cs create mode 100644 src/Spectre.Console/IAnsiConsoleOutput.cs create mode 100644 src/Spectre.Console/Internal/Text/Encoding/EncoderCapabilities.cs diff --git a/examples/Console/Colors/Program.cs b/examples/Console/Colors/Program.cs index 5e7708d..b73fc50 100644 --- a/examples/Console/Colors/Program.cs +++ b/examples/Console/Colors/Program.cs @@ -7,7 +7,7 @@ namespace Spectre.Console.Examples ///////////////////////////////////////////////////////////////// // No colors ///////////////////////////////////////////////////////////////// - if (AnsiConsole.Profile.ColorSystem == ColorSystem.NoColors) + if (AnsiConsole.Profile.Capabilities.ColorSystem == ColorSystem.NoColors) { AnsiConsole.WriteLine("No colors are supported."); return; diff --git a/examples/Console/Info/Program.cs b/examples/Console/Info/Program.cs index 2d757df..304836a 100644 --- a/examples/Console/Info/Program.cs +++ b/examples/Console/Info/Program.cs @@ -8,13 +8,13 @@ namespace Spectre.Console.Examples .AddColumn(new GridColumn().NoWrap().PadRight(4)) .AddColumn() .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]Supports ansi?[/]", $"{YesNo(AnsiConsole.Profile.Capabilities.Ansi)}") .AddRow("[b]Supports links?[/]", $"{YesNo(AnsiConsole.Profile.Capabilities.Links)}") .AddRow("[b]Legacy console?[/]", $"{YesNo(AnsiConsole.Profile.Capabilities.Legacy)}") .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 height[/]", $"{AnsiConsole.Console.Profile.Height}") .AddRow("[b]Encoding[/]", $"{AnsiConsole.Console.Profile.Encoding.EncodingName}"); diff --git a/src/Spectre.Console.Testing/Fakes/FakeAnsiConsole.cs b/src/Spectre.Console.Testing/Fakes/FakeAnsiConsole.cs index da1f36d..2e1149c 100644 --- a/src/Spectre.Console.Testing/Fakes/FakeAnsiConsole.cs +++ b/src/Spectre.Console.Testing/Fakes/FakeAnsiConsole.cs @@ -33,7 +33,7 @@ namespace Spectre.Console.Testing { Ansi = ansi, ColorSystem = (ColorSystemSupport)colors, - Out = _writer, + Out = new AnsiConsoleOutput(_writer), Enrichment = new ProfileEnrichment { UseDefaultEnrichers = false, diff --git a/src/Spectre.Console.Testing/Fakes/FakeCapabilities.cs b/src/Spectre.Console.Testing/Fakes/FakeCapabilities.cs index 85547e1..6feedea 100644 --- a/src/Spectre.Console.Testing/Fakes/FakeCapabilities.cs +++ b/src/Spectre.Console.Testing/Fakes/FakeCapabilities.cs @@ -2,13 +2,15 @@ namespace Spectre.Console.Testing { public sealed class FakeCapabilities : IReadOnlyCapabilities { + public ColorSystem ColorSystem { get; set; } = ColorSystem.TrueColor; + public bool Ansi { get; set; } public bool Links { get; set; } public bool Legacy { get; set; } - public bool Tty { get; set; } + public bool IsTerminal { get; set; } public bool Interactive { get; set; } diff --git a/src/Spectre.Console.Testing/Fakes/FakeConsole.cs b/src/Spectre.Console.Testing/Fakes/FakeConsole.cs index 8474fe9..335de66 100644 --- a/src/Spectre.Console.Testing/Fakes/FakeConsole.cs +++ b/src/Spectre.Console.Testing/Fakes/FakeConsole.cs @@ -16,7 +16,7 @@ namespace Spectre.Console.Testing public RenderPipeline Pipeline { get; } public FakeConsoleInput Input { get; } - public string Output => Profile.Out.ToString(); + public string Output => Profile.Out.Writer.ToString(); public IReadOnlyList Lines => Output.TrimEnd('\n').Split(new char[] { '\n' }); public FakeConsole( @@ -28,10 +28,10 @@ namespace Spectre.Console.Testing ExclusivityMode = new FakeExclusivityMode(); 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.Height = height; - Profile.ColorSystem = colorSystem; + Profile.Capabilities.ColorSystem = colorSystem; Profile.Capabilities.Ansi = supportsAnsi; Profile.Capabilities.Legacy = legacyConsole; Profile.Capabilities.Interactive = interactive; @@ -41,7 +41,7 @@ namespace Spectre.Console.Testing public void Dispose() { - Profile.Out.Dispose(); + Profile.Out.Writer.Dispose(); } public void Clear(bool home) @@ -52,7 +52,7 @@ namespace Spectre.Console.Testing { foreach (var segment in renderable.GetSegments(this)) { - Profile.Out.Write(segment.Text); + Profile.Out.Writer.Write(segment.Text); } } diff --git a/src/Spectre.Console.Tests/Unit/AnsiConsoleTests.Colors.cs b/src/Spectre.Console.Tests/Unit/AnsiConsoleTests.Colors.cs index a07c1f5..c03ebe6 100644 --- a/src/Spectre.Console.Tests/Unit/AnsiConsoleTests.Colors.cs +++ b/src/Spectre.Console.Tests/Unit/AnsiConsoleTests.Colors.cs @@ -19,11 +19,11 @@ namespace Spectre.Console.Tests.Unit var console = AnsiConsole.Create(new AnsiConsoleSettings { ColorSystem = requested, - Out = new StringWriter(), + Out = new AnsiConsoleOutput(new StringWriter()), }); // Then - console.Profile.ColorSystem.ShouldBe(expected); + console.Profile.Capabilities.ColorSystem.ShouldBe(expected); } public sealed class TrueColor diff --git a/src/Spectre.Console.Tests/Unit/Progress/ProgressColumnFixture.cs b/src/Spectre.Console.Tests/Unit/Progress/ProgressColumnFixture.cs index 58a51bd..9d2550c 100644 --- a/src/Spectre.Console.Tests/Unit/Progress/ProgressColumnFixture.cs +++ b/src/Spectre.Console.Tests/Unit/Progress/ProgressColumnFixture.cs @@ -20,7 +20,7 @@ namespace Spectre.Console.Tests.Unit public string Render() { 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)); return console.Output; } diff --git a/src/Spectre.Console.Tests/Unit/RuleTests.cs b/src/Spectre.Console.Tests/Unit/RuleTests.cs index 71a8358..36d98d7 100644 --- a/src/Spectre.Console.Tests/Unit/RuleTests.cs +++ b/src/Spectre.Console.Tests/Unit/RuleTests.cs @@ -130,7 +130,6 @@ namespace Spectre.Console.Tests.Unit } [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(2, "Hello World Hello World Hello World Hello World Hello World", "──")] [InlineData(3, "Hello World Hello World Hello World Hello World Hello World", "───")] diff --git a/src/Spectre.Console.Tests/Unit/TextTests.cs b/src/Spectre.Console.Tests/Unit/TextTests.cs index 013a499..6504779 100644 --- a/src/Spectre.Console.Tests/Unit/TextTests.cs +++ b/src/Spectre.Console.Tests/Unit/TextTests.cs @@ -15,7 +15,7 @@ namespace Spectre.Console.Tests.Unit var text = new Text("Foo Bar Baz\nQux\nLol mobile"); // When - var result = ((IRenderable)text).Measure(new RenderContext(ColorSystem.TrueColor, caps), 80); + var result = ((IRenderable)text).Measure(new RenderContext(caps), 80); // Then result.Min.ShouldBe(6); @@ -29,7 +29,7 @@ namespace Spectre.Console.Tests.Unit var text = new Text("Foo Bar Baz\nQux\nLol mobile"); // When - var result = ((IRenderable)text).Measure(new RenderContext(ColorSystem.TrueColor, caps), 80); + var result = ((IRenderable)text).Measure(new RenderContext(caps), 80); // Then result.Max.ShouldBe(11); diff --git a/src/Spectre.Console/AnsiConsole.cs b/src/Spectre.Console/AnsiConsole.cs index 2baebf8..85cf2c7 100644 --- a/src/Spectre.Console/AnsiConsole.cs +++ b/src/Spectre.Console/AnsiConsole.cs @@ -15,7 +15,7 @@ namespace Spectre.Console { Ansi = AnsiSupport.Detect, ColorSystem = ColorSystemSupport.Detect, - Out = System.Console.Out, + Out = new AnsiConsoleOutput(System.Console.Out), }); Created = true; diff --git a/src/Spectre.Console/AnsiConsoleFactory.cs b/src/Spectre.Console/AnsiConsoleFactory.cs index 43194c4..3d8e0e5 100644 --- a/src/Spectre.Console/AnsiConsoleFactory.cs +++ b/src/Spectre.Console/AnsiConsoleFactory.cs @@ -22,13 +22,18 @@ namespace Spectre.Console 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 - var (supportsAnsi, legacyConsole) = DetectAnsi(settings, buffer); + var (supportsAnsi, legacyConsole) = DetectAnsi(settings, output.Writer); // 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 var colorSystem = settings.ColorSystem == ColorSystemSupport.Detect @@ -42,11 +47,9 @@ namespace Spectre.Console interactive = Environment.UserInteractive; } - var profile = new Profile(buffer, encoding) - { - ColorSystem = colorSystem, - }; + var profile = new Profile(output, encoding); + profile.Capabilities.ColorSystem = colorSystem; profile.Capabilities.Ansi = supportsAnsi; profile.Capabilities.Links = supportsAnsi && !legacyConsole; profile.Capabilities.Legacy = legacyConsole; diff --git a/src/Spectre.Console/AnsiConsoleOutput.cs b/src/Spectre.Console/AnsiConsoleOutput.cs new file mode 100644 index 0000000..907def7 --- /dev/null +++ b/src/Spectre.Console/AnsiConsoleOutput.cs @@ -0,0 +1,58 @@ +using System; +using System.IO; +using System.Text; + +namespace Spectre.Console +{ + /// + /// Represents console output. + /// + public sealed class AnsiConsoleOutput : IAnsiConsoleOutput + { + /// + public TextWriter Writer { get; } + + /// + public bool IsTerminal + { + get + { + if (Writer.IsStandardOut()) + { + return !System.Console.IsOutputRedirected; + } + + if (Writer.IsStandardError()) + { + return !System.Console.IsErrorRedirected; + } + + return false; + } + } + + /// + public int Width => ConsoleHelper.GetSafeWidth(Constants.DefaultTerminalWidth); + + /// + public int Height => ConsoleHelper.GetSafeHeight(Constants.DefaultTerminalWidth); + + /// + /// Initializes a new instance of the class. + /// + /// The output writer. + public AnsiConsoleOutput(TextWriter writer) + { + Writer = writer ?? throw new ArgumentNullException(nameof(writer)); + } + + /// + public void SetEncoding(Encoding encoding) + { + if (Writer.IsStandardOut() || Writer.IsStandardError()) + { + System.Console.OutputEncoding = encoding; + } + } + } +} diff --git a/src/Spectre.Console/AnsiConsoleSettings.cs b/src/Spectre.Console/AnsiConsoleSettings.cs index 6fee233..7038eb2 100644 --- a/src/Spectre.Console/AnsiConsoleSettings.cs +++ b/src/Spectre.Console/AnsiConsoleSettings.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.IO; namespace Spectre.Console { @@ -22,7 +21,7 @@ namespace Spectre.Console /// /// Gets or sets the out buffer. /// - public TextWriter? Out { get; set; } + public IAnsiConsoleOutput? Out { get; set; } /// /// Gets or sets a value indicating whether or not the diff --git a/src/Spectre.Console/Capabilities.cs b/src/Spectre.Console/Capabilities.cs index 98effac..2c367b8 100644 --- a/src/Spectre.Console/Capabilities.cs +++ b/src/Spectre.Console/Capabilities.cs @@ -7,7 +7,12 @@ namespace Spectre.Console /// public sealed class Capabilities : IReadOnlyCapabilities { - private readonly Profile _profile; + private readonly IAnsiConsoleOutput _out; + + /// + /// Gets or sets the color system. + /// + public ColorSystem ColorSystem { get; set; } /// /// Gets or sets a value indicating whether or not @@ -33,26 +38,10 @@ namespace Spectre.Console /// /// Gets a value indicating whether or not - /// console output has been redirected. + /// the output is a terminal. /// - public bool Tty - { - 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; - } - } + [Obsolete("Use Profile.Out.IsTerminal instead")] + public bool IsTerminal => _out.IsTerminal; /// /// Gets or sets a value indicating whether @@ -67,11 +56,12 @@ namespace Spectre.Console public bool Unicode { get; set; } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the + /// class. /// - internal Capabilities(Profile profile) + internal Capabilities(IAnsiConsoleOutput @out) { - _profile = profile ?? throw new ArgumentNullException(nameof(profile)); + _out = @out ?? throw new ArgumentNullException(nameof(@out)); } } } diff --git a/src/Spectre.Console/Extensions/RenderableExtensions.cs b/src/Spectre.Console/Extensions/RenderableExtensions.cs index c7ca2ef..acc2fa5 100644 --- a/src/Spectre.Console/Extensions/RenderableExtensions.cs +++ b/src/Spectre.Console/Extensions/RenderableExtensions.cs @@ -27,7 +27,7 @@ namespace Spectre.Console 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 }); return GetSegments(console, context, renderables); diff --git a/src/Spectre.Console/IAnsiConsoleOutput.cs b/src/Spectre.Console/IAnsiConsoleOutput.cs new file mode 100644 index 0000000..395a469 --- /dev/null +++ b/src/Spectre.Console/IAnsiConsoleOutput.cs @@ -0,0 +1,37 @@ +using System.IO; +using System.Text; + +namespace Spectre.Console +{ + /// + /// Represents console output. + /// + public interface IAnsiConsoleOutput + { + /// + /// Gets the used to write to the output. + /// + TextWriter Writer { get; } + + /// + /// Gets a value indicating whether or not the output is a terminal. + /// + bool IsTerminal { get; } + + /// + /// Gets the output width. + /// + int Width { get; } + + /// + /// Gets the output height. + /// + int Height { get; } + + /// + /// Sets the output encoding. + /// + /// The encoding. + void SetEncoding(Encoding encoding); + } +} diff --git a/src/Spectre.Console/IReadOnlyCapabilities.cs b/src/Spectre.Console/IReadOnlyCapabilities.cs index e624a01..340f338 100644 --- a/src/Spectre.Console/IReadOnlyCapabilities.cs +++ b/src/Spectre.Console/IReadOnlyCapabilities.cs @@ -1,3 +1,5 @@ +using System; + namespace Spectre.Console { /// @@ -5,6 +7,11 @@ namespace Spectre.Console /// public interface IReadOnlyCapabilities { + /// + /// Gets the color system. + /// + ColorSystem ColorSystem { get; } + /// /// Gets a value indicating whether or not /// the console supports Ansi. @@ -31,7 +38,8 @@ namespace Spectre.Console /// Gets a value indicating whether or not /// console output has been redirected. /// - bool Tty { get; } + [Obsolete("Use Profile.Out.IsTerminal instead")] + bool IsTerminal { get; } /// /// Gets a value indicating whether diff --git a/src/Spectre.Console/Internal/Backends/Ansi/AnsiBuilder.cs b/src/Spectre.Console/Internal/Backends/Ansi/AnsiBuilder.cs index 2f73547..de64b7b 100644 --- a/src/Spectre.Console/Internal/Backends/Ansi/AnsiBuilder.cs +++ b/src/Spectre.Console/Internal/Backends/Ansi/AnsiBuilder.cs @@ -29,7 +29,7 @@ namespace Spectre.Console { codes = codes.Concat( AnsiColorBuilder.GetAnsiCodes( - _profile.ColorSystem, + _profile.Capabilities.ColorSystem, style.Foreground, true)); } @@ -39,7 +39,7 @@ namespace Spectre.Console { codes = codes.Concat( AnsiColorBuilder.GetAnsiCodes( - _profile.ColorSystem, + _profile.Capabilities.ColorSystem, style.Background, false)); } diff --git a/src/Spectre.Console/Internal/Backends/Ansi/AnsiConsoleBackend.cs b/src/Spectre.Console/Internal/Backends/Ansi/AnsiConsoleBackend.cs index 884e498..72addb5 100644 --- a/src/Spectre.Console/Internal/Backends/Ansi/AnsiConsoleBackend.cs +++ b/src/Spectre.Console/Internal/Backends/Ansi/AnsiConsoleBackend.cs @@ -59,8 +59,8 @@ namespace Spectre.Console if (builder.Length > 0) { - _console.Profile.Out.Write(builder.ToString()); - _console.Profile.Out.Flush(); + _console.Profile.Out.Writer.Write(builder.ToString()); + _console.Profile.Out.Writer.Flush(); } } } diff --git a/src/Spectre.Console/Internal/Backends/Legacy/LegacyConsoleBackend.cs b/src/Spectre.Console/Internal/Backends/Legacy/LegacyConsoleBackend.cs index 94de396..80d4b6c 100644 --- a/src/Spectre.Console/Internal/Backends/Legacy/LegacyConsoleBackend.cs +++ b/src/Spectre.Console/Internal/Backends/Legacy/LegacyConsoleBackend.cs @@ -44,7 +44,7 @@ namespace Spectre.Console 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(); 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; } 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; } diff --git a/src/Spectre.Console/Internal/DefaultInput.cs b/src/Spectre.Console/Internal/DefaultInput.cs index 844db0f..0165c52 100644 --- a/src/Spectre.Console/Internal/DefaultInput.cs +++ b/src/Spectre.Console/Internal/DefaultInput.cs @@ -13,11 +13,6 @@ namespace Spectre.Console public ConsoleKeyInfo ReadKey(bool intercept) { - if (_profile.Capabilities.Tty) - { - throw new InvalidOperationException("Cannot read input from a TTY console."); - } - if (!_profile.Capabilities.Interactive) { throw new InvalidOperationException("Failed to read input in non-interactive mode."); diff --git a/src/Spectre.Console/Internal/Text/Encoding/EncoderCapabilities.cs b/src/Spectre.Console/Internal/Text/Encoding/EncoderCapabilities.cs new file mode 100644 index 0000000..88d5fae --- /dev/null +++ b/src/Spectre.Console/Internal/Text/Encoding/EncoderCapabilities.cs @@ -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; + } + } +} diff --git a/src/Spectre.Console/Internal/Text/Encoding/HtmlEncoder.cs b/src/Spectre.Console/Internal/Text/Encoding/HtmlEncoder.cs index f3cc883..ac12c1a 100644 --- a/src/Spectre.Console/Internal/Text/Encoding/HtmlEncoder.cs +++ b/src/Spectre.Console/Internal/Text/Encoding/HtmlEncoder.cs @@ -9,7 +9,7 @@ namespace Spectre.Console.Internal { public string Encode(IAnsiConsole console, IEnumerable renderables) { - var context = new RenderContext(ColorSystem.TrueColor, EncoderCapabilities.Default); + var context = new RenderContext(new EncoderCapabilities(ColorSystem.TrueColor)); var builder = new StringBuilder(); builder.Append("
\n");
diff --git a/src/Spectre.Console/Internal/Text/Encoding/TextEncoder.cs b/src/Spectre.Console/Internal/Text/Encoding/TextEncoder.cs
index 954ead2..92597bf 100644
--- a/src/Spectre.Console/Internal/Text/Encoding/TextEncoder.cs
+++ b/src/Spectre.Console/Internal/Text/Encoding/TextEncoder.cs
@@ -4,23 +4,11 @@ using Spectre.Console.Rendering;
 
 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
     {
         public string Encode(IAnsiConsole console, IEnumerable renderables)
         {
-            var context = new RenderContext(ColorSystem.TrueColor, EncoderCapabilities.Default);
+            var context = new RenderContext(new EncoderCapabilities(ColorSystem.TrueColor));
             var builder = new StringBuilder();
 
             foreach (var renderable in renderables)
diff --git a/src/Spectre.Console/Profile.cs b/src/Spectre.Console/Profile.cs
index 0ef06ca..3a82c2b 100644
--- a/src/Spectre.Console/Profile.cs
+++ b/src/Spectre.Console/Profile.cs
@@ -1,6 +1,5 @@
 using System;
 using System.Collections.Generic;
-using System.IO;
 using System.Text;
 
 namespace Spectre.Console
@@ -13,7 +12,7 @@ namespace Spectre.Console
         private readonly HashSet _enrichers;
         private static readonly string[] _defaultEnricher = new[] { "Default" };
 
-        private TextWriter _out;
+        private IAnsiConsoleOutput _out;
         private Encoding _encoding;
         private Capabilities _capabilities;
         private int? _width;
@@ -38,15 +37,15 @@ namespace Spectre.Console
         /// 
         /// Gets or sets the out buffer.
         /// 
-        public TextWriter Out
+        public IAnsiConsoleOutput Out
         {
             get => _out;
             set
             {
                 _out = value ?? throw new InvalidOperationException("Output buffer cannot be null");
 
-                // Reset the width and height if not a TTY.
-                if (!Capabilities.Tty)
+                // Reset the width and height if this is a terminal.
+                if (value.IsTerminal)
                 {
                     _width = null;
                     _height = null;
@@ -67,12 +66,7 @@ namespace Spectre.Console
                     throw new InvalidOperationException("Encoding cannot be null");
                 }
 
-                // Need to update the output encoding for stdout?
-                if (_out.IsStandardOut() || _out.IsStandardError())
-                {
-                    System.Console.OutputEncoding = value;
-                }
-
+                _out.SetEncoding(value);
                 _encoding = value;
             }
         }
@@ -82,10 +76,10 @@ namespace Spectre.Console
         /// 
public int Width { - get => GetWidth(); + get => _width ?? _out.Width; set { - if (_width <= 0) + if (value <= 0) { throw new InvalidOperationException("Console width must be greater than zero"); } @@ -99,10 +93,10 @@ namespace Spectre.Console ///
public int Height { - get => GetHeight(); + get => _height ?? _out.Height; set { - if (_height <= 0) + if (value <= 0) { throw new InvalidOperationException("Console height must be greater than zero"); } @@ -111,11 +105,6 @@ namespace Spectre.Console } } - /// - /// Gets or sets the color system. - /// - public ColorSystem ColorSystem { get; set; } - /// /// Gets or sets the capabilities of the profile. /// @@ -133,12 +122,12 @@ namespace Spectre.Console ///
/// The output buffer. /// The output encoding. - public Profile(TextWriter @out, Encoding encoding) + public Profile(IAnsiConsoleOutput @out, Encoding encoding) { _enrichers = new HashSet(StringComparer.OrdinalIgnoreCase); _out = @out ?? throw new ArgumentNullException(nameof(@out)); _encoding = encoding ?? throw new ArgumentNullException(nameof(encoding)); - _capabilities = new Capabilities(this); + _capabilities = new Capabilities(_out); } /// @@ -149,7 +138,7 @@ namespace Spectre.Console /// true if the color system is supported, otherwise false. public bool Supports(ColorSystem colorSystem) { - return (int)colorSystem <= (int)ColorSystem; + return (int)colorSystem <= (int)Capabilities.ColorSystem; } internal void AddEnricher(string name) @@ -161,35 +150,5 @@ namespace Spectre.Console _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; - } } } diff --git a/src/Spectre.Console/Rendering/RenderContext.cs b/src/Spectre.Console/Rendering/RenderContext.cs index fd10a79..b4ffff1 100644 --- a/src/Spectre.Console/Rendering/RenderContext.cs +++ b/src/Spectre.Console/Rendering/RenderContext.cs @@ -12,7 +12,7 @@ namespace Spectre.Console.Rendering /// /// Gets the current color system. /// - public ColorSystem ColorSystem { get; } + public ColorSystem ColorSystem => _capabilities.ColorSystem; /// /// Gets a value indicating whether or not unicode is supported. @@ -33,19 +33,17 @@ namespace Spectre.Console.Rendering /// /// Initializes a new instance of the class. /// - /// The color system. /// The capabilities. /// The justification. - public RenderContext(ColorSystem colorSystem, IReadOnlyCapabilities capabilities, Justify? justification = null) - : this(colorSystem, capabilities, justification, false) + public RenderContext(IReadOnlyCapabilities capabilities, Justify? justification = null) + : 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)); - ColorSystem = colorSystem; Justification = justification; SingleLine = singleLine; } @@ -57,7 +55,7 @@ namespace Spectre.Console.Rendering /// A new instance. public RenderContext WithJustification(Justify? justification) { - return new RenderContext(ColorSystem, _capabilities, justification, SingleLine); + return new RenderContext(_capabilities, justification, SingleLine); } /// @@ -72,7 +70,7 @@ namespace Spectre.Console.Rendering /// A new instance. internal RenderContext WithSingleLine() { - return new RenderContext(ColorSystem, _capabilities, Justification, true); + return new RenderContext(_capabilities, Justification, true); } } } diff --git a/src/Spectre.Console/Widgets/Progress/Renderers/DefaultProgressRenderer.cs b/src/Spectre.Console/Widgets/Progress/Renderers/DefaultProgressRenderer.cs index 7122fa7..c764531 100644 --- a/src/Spectre.Console/Widgets/Progress/Renderers/DefaultProgressRenderer.cs +++ b/src/Spectre.Console/Widgets/Progress/Renderers/DefaultProgressRenderer.cs @@ -62,7 +62,7 @@ namespace Spectre.Console _stopwatch.Start(); } - var renderContext = new RenderContext(_console.Profile.ColorSystem, _console.Profile.Capabilities); + var renderContext = new RenderContext(_console.Profile.Capabilities); var delta = _stopwatch.Elapsed - _lastUpdate; _lastUpdate = _stopwatch.Elapsed;