From 4bdd3ccc6c4d9e019a32536d7d6033cd23765fcc Mon Sep 17 00:00:00 2001 From: Tyrrrz <1935960+Tyrrrz@users.noreply.github.com> Date: Tue, 23 Jan 2024 23:30:27 +0200 Subject: [PATCH] Refactor --- CliFx/Attributes/CommandAttribute.cs | 23 ++++----- CliFx/Attributes/CommandOptionAttribute.cs | 54 ++++++++++----------- CliFx/Infrastructure/ConsoleReader.cs | 10 +--- CliFx/Infrastructure/ConsoleWriter.cs | 21 ++++---- CliFx/Infrastructure/FakeConsole.cs | 37 +++++++------- CliFx/Infrastructure/FakeInMemoryConsole.cs | 6 +-- CliFx/Infrastructure/IConsole.cs | 18 +++---- CliFx/Infrastructure/SystemConsole.cs | 20 ++++---- 8 files changed, 91 insertions(+), 98 deletions(-) diff --git a/CliFx/Attributes/CommandAttribute.cs b/CliFx/Attributes/CommandAttribute.cs index 6c97f95..2066428 100644 --- a/CliFx/Attributes/CommandAttribute.cs +++ b/CliFx/Attributes/CommandAttribute.cs @@ -8,6 +8,16 @@ namespace CliFx.Attributes; [AttributeUsage(AttributeTargets.Class, Inherited = false)] public sealed class CommandAttribute : Attribute { + /// + /// Initializes an instance of . + /// + public CommandAttribute(string name) => Name = name; + + /// + /// Initializes an instance of . + /// + public CommandAttribute() { } + /// /// Command name. /// @@ -23,17 +33,4 @@ public sealed class CommandAttribute : Attribute /// This is shown to the user in the help text. /// public string? Description { get; set; } - - /// - /// Initializes an instance of . - /// - public CommandAttribute(string name) - { - Name = name; - } - - /// - /// Initializes an instance of . - /// - public CommandAttribute() { } } diff --git a/CliFx/Attributes/CommandOptionAttribute.cs b/CliFx/Attributes/CommandOptionAttribute.cs index f4c4343..96d237a 100644 --- a/CliFx/Attributes/CommandOptionAttribute.cs +++ b/CliFx/Attributes/CommandOptionAttribute.cs @@ -9,6 +9,33 @@ namespace CliFx.Attributes; [AttributeUsage(AttributeTargets.Property)] public sealed class CommandOptionAttribute : Attribute { + /// + /// Initializes an instance of . + /// + private CommandOptionAttribute(string? name, char? shortName) + { + Name = name; + ShortName = shortName; + } + + /// + /// Initializes an instance of . + /// + public CommandOptionAttribute(string name, char shortName) + : this(name, (char?)shortName) { } + + /// + /// Initializes an instance of . + /// + public CommandOptionAttribute(string name) + : this(name, null) { } + + /// + /// Initializes an instance of . + /// + public CommandOptionAttribute(char shortName) + : this(null, (char?)shortName) { } + /// /// Option name. /// @@ -67,31 +94,4 @@ public sealed class CommandOptionAttribute : Attribute /// Validators must derive from . /// public Type[] Validators { get; set; } = Array.Empty(); - - /// - /// Initializes an instance of . - /// - private CommandOptionAttribute(string? name, char? shortName) - { - Name = name; - ShortName = shortName; - } - - /// - /// Initializes an instance of . - /// - public CommandOptionAttribute(string name, char shortName) - : this(name, (char?)shortName) { } - - /// - /// Initializes an instance of . - /// - public CommandOptionAttribute(string name) - : this(name, null) { } - - /// - /// Initializes an instance of . - /// - public CommandOptionAttribute(char shortName) - : this(null, (char?)shortName) { } } diff --git a/CliFx/Infrastructure/ConsoleReader.cs b/CliFx/Infrastructure/ConsoleReader.cs index 69f7dd2..ef83201 100644 --- a/CliFx/Infrastructure/ConsoleReader.cs +++ b/CliFx/Infrastructure/ConsoleReader.cs @@ -11,8 +11,8 @@ namespace CliFx.Infrastructure; /// // Both the underlying stream AND the stream reader must be synchronized! // https://github.com/Tyrrrz/CliFx/issues/123 -public partial class ConsoleReader(IConsole console, Stream stream, Encoding encoding) - : StreamReader(stream, encoding, false, 4096) +public class ConsoleReader(IConsole console, Stream stream, Encoding encoding) + : StreamReader(Stream.Synchronized(stream), encoding, false, 4096) { /// /// Initializes an instance of . @@ -86,9 +86,3 @@ public partial class ConsoleReader(IConsole console, Stream stream, Encoding enc [ExcludeFromCodeCoverage, MethodImpl(MethodImplOptions.Synchronized)] protected override void Dispose(bool disposing) => base.Dispose(disposing); } - -public partial class ConsoleReader -{ - internal static ConsoleReader Create(IConsole console, Stream stream) => - new(console, Stream.Synchronized(stream)); -} diff --git a/CliFx/Infrastructure/ConsoleWriter.cs b/CliFx/Infrastructure/ConsoleWriter.cs index 17676b1..9222859 100644 --- a/CliFx/Infrastructure/ConsoleWriter.cs +++ b/CliFx/Infrastructure/ConsoleWriter.cs @@ -12,9 +12,18 @@ namespace CliFx.Infrastructure; /// // Both the underlying stream AND the stream writer must be synchronized! // https://github.com/Tyrrrz/CliFx/issues/123 -public partial class ConsoleWriter(IConsole console, Stream stream, Encoding encoding) - : StreamWriter(stream, encoding.WithoutPreamble(), 256) +public class ConsoleWriter : StreamWriter { + /// + /// Initializes an instance of . + /// + public ConsoleWriter(IConsole console, Stream stream, Encoding encoding) + : base(Stream.Synchronized(stream), encoding.WithoutPreamble(), 256) + { + Console = console; + AutoFlush = true; + } + /// /// Initializes an instance of . /// @@ -24,7 +33,7 @@ public partial class ConsoleWriter(IConsole console, Stream stream, Encoding enc /// /// Console that owns this stream. /// - public IConsole Console { get; } = console; + public IConsole Console { get; } // The following overrides are required to establish thread-safe behavior // in methods deriving from StreamWriter. @@ -260,9 +269,3 @@ public partial class ConsoleWriter(IConsole console, Stream stream, Encoding enc [ExcludeFromCodeCoverage, MethodImpl(MethodImplOptions.Synchronized)] protected override void Dispose(bool disposing) => base.Dispose(disposing); } - -public partial class ConsoleWriter -{ - internal static ConsoleWriter Create(IConsole console, Stream stream) => - new(console, Stream.Synchronized(stream)) { AutoFlush = true }; -} diff --git a/CliFx/Infrastructure/FakeConsole.cs b/CliFx/Infrastructure/FakeConsole.cs index 2ef7622..5497389 100644 --- a/CliFx/Infrastructure/FakeConsole.cs +++ b/CliFx/Infrastructure/FakeConsole.cs @@ -6,15 +6,24 @@ using System.Threading; namespace CliFx.Infrastructure; /// -/// Implementation of that uses the provided fake -/// standard input, output, and error streams. -/// Use this implementation in tests to verify command interactions with the console. +/// Implementation of that uses the provided fake standard input, output, and error streams. +/// Use this implementation in tests to verify how a command interacts with the console. /// public class FakeConsole : IConsole, IDisposable { private readonly CancellationTokenSource _cancellationTokenSource = new(); private readonly ConcurrentQueue _keys = new(); + /// + /// Initializes an instance of . + /// + public FakeConsole(Stream? input = null, Stream? output = null, Stream? error = null) + { + Input = new ConsoleReader(this, input ?? Stream.Null); + Output = new ConsoleWriter(this, output ?? Stream.Null); + Error = new ConsoleWriter(this, error ?? Stream.Null); + } + /// public ConsoleReader Input { get; } @@ -52,14 +61,9 @@ public class FakeConsole : IConsole, IDisposable public int CursorTop { get; set; } /// - /// Initializes an instance of . + /// Enqueues a simulated key press, which can then be read by calling . /// - public FakeConsole(Stream? input = null, Stream? output = null, Stream? error = null) - { - Input = ConsoleReader.Create(this, input ?? Stream.Null); - Output = ConsoleWriter.Create(this, output ?? Stream.Null); - Error = ConsoleWriter.Create(this, error ?? Stream.Null); - } + public void EnqueueKey(ConsoleKeyInfo key) => _keys.Enqueue(key); /// public ConsoleKeyInfo ReadKey(bool intercept = false) => @@ -70,11 +74,6 @@ public class FakeConsole : IConsole, IDisposable + $"Use the `{nameof(EnqueueKey)}(...)` method to simulate a key press." ); - /// - /// Enqueues a simulated key press, which can then be read by calling . - /// - public void EnqueueKey(ConsoleKeyInfo key) => _keys.Enqueue(key); - /// public void ResetColor() { @@ -85,11 +84,8 @@ public class FakeConsole : IConsole, IDisposable /// public void Clear() { } - /// - public CancellationToken RegisterCancellationHandler() => _cancellationTokenSource.Token; - /// - /// Sends a cancellation signal to the currently executing command. + /// Simulates a cancellation request. /// /// /// If the command is not cancellation-aware (i.e. it doesn't call ), @@ -108,6 +104,9 @@ public class FakeConsole : IConsole, IDisposable } } + /// + public CancellationToken RegisterCancellationHandler() => _cancellationTokenSource.Token; + /// public virtual void Dispose() => _cancellationTokenSource.Dispose(); } diff --git a/CliFx/Infrastructure/FakeInMemoryConsole.cs b/CliFx/Infrastructure/FakeInMemoryConsole.cs index daac26d..0be8646 100644 --- a/CliFx/Infrastructure/FakeInMemoryConsole.cs +++ b/CliFx/Infrastructure/FakeInMemoryConsole.cs @@ -3,9 +3,9 @@ namespace CliFx.Infrastructure; /// -/// Implementation of that uses fake -/// standard input, output, and error streams backed by in-memory stores. -/// Use this implementation in tests to verify command interactions with the console. +/// Implementation of that uses fake standard input, output, and error streams +/// backed by in-memory stores. +/// Use this implementation in tests to verify how a command interacts with the console. /// public class FakeInMemoryConsole : FakeConsole { diff --git a/CliFx/Infrastructure/IConsole.cs b/CliFx/Infrastructure/IConsole.cs index 32e1071..50e5c39 100644 --- a/CliFx/Infrastructure/IConsole.cs +++ b/CliFx/Infrastructure/IConsole.cs @@ -5,47 +5,47 @@ using CliFx.Utils; namespace CliFx.Infrastructure; /// -/// Abstraction for the console layer. +/// Abstraction for interacting with the console layer. /// public interface IConsole { /// - /// Input stream (stdin). + /// Console's standard input stream. /// ConsoleReader Input { get; } /// - /// Gets a value that indicates whether input has been redirected from the standard input stream. + /// Whether the input stream has been redirected. /// bool IsInputRedirected { get; } /// - /// Output stream (stdout). + /// Console's standard output stream. /// ConsoleWriter Output { get; } /// - /// Gets a value that indicates whether output has been redirected from the standard output stream. + /// Whether the output stream has been redirected. /// bool IsOutputRedirected { get; } /// - /// Error stream (stderr). + /// Console's standard error stream. /// ConsoleWriter Error { get; } /// - /// Gets a value that indicates whether error output has been redirected from the standard error stream. + /// Whether the error stream has been redirected. /// bool IsErrorRedirected { get; } /// - /// Gets or sets the foreground color of the console + /// Gets or sets the current foreground color of the console. /// ConsoleColor ForegroundColor { get; set; } /// - /// Gets or sets the background color of the console. + /// Gets or sets the current background color of the console. /// ConsoleColor BackgroundColor { get; set; } diff --git a/CliFx/Infrastructure/SystemConsole.cs b/CliFx/Infrastructure/SystemConsole.cs index a253782..f696637 100644 --- a/CliFx/Infrastructure/SystemConsole.cs +++ b/CliFx/Infrastructure/SystemConsole.cs @@ -10,6 +10,16 @@ public class SystemConsole : IConsole, IDisposable { private CancellationTokenSource? _cancellationTokenSource; + /// + /// Initializes an instance of . + /// + public SystemConsole() + { + Input = new ConsoleReader(this, Console.OpenStandardInput()); + Output = new ConsoleWriter(this, Console.OpenStandardOutput()); + Error = new ConsoleWriter(this, Console.OpenStandardError()); + } + /// public ConsoleReader Input { get; } @@ -70,16 +80,6 @@ public class SystemConsole : IConsole, IDisposable set => Console.CursorTop = value; } - /// - /// Initializes an instance of . - /// - public SystemConsole() - { - Input = ConsoleReader.Create(this, Console.OpenStandardInput()); - Output = ConsoleWriter.Create(this, Console.OpenStandardOutput()); - Error = ConsoleWriter.Create(this, Console.OpenStandardError()); - } - /// public ConsoleKeyInfo ReadKey(bool intercept = false) => Console.ReadKey(intercept);