mirror of
https://github.com/Tyrrrz/CliFx.git
synced 2025-10-25 15:19:17 +00:00
Refactor
This commit is contained in:
@@ -8,6 +8,16 @@ namespace CliFx.Attributes;
|
||||
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
|
||||
public sealed class CommandAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes an instance of <see cref="CommandAttribute" />.
|
||||
/// </summary>
|
||||
public CommandAttribute(string name) => Name = name;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes an instance of <see cref="CommandAttribute" />.
|
||||
/// </summary>
|
||||
public CommandAttribute() { }
|
||||
|
||||
/// <summary>
|
||||
/// Command name.
|
||||
/// </summary>
|
||||
@@ -23,17 +33,4 @@ public sealed class CommandAttribute : Attribute
|
||||
/// This is shown to the user in the help text.
|
||||
/// </summary>
|
||||
public string? Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes an instance of <see cref="CommandAttribute" />.
|
||||
/// </summary>
|
||||
public CommandAttribute(string name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes an instance of <see cref="CommandAttribute" />.
|
||||
/// </summary>
|
||||
public CommandAttribute() { }
|
||||
}
|
||||
|
||||
@@ -9,6 +9,33 @@ namespace CliFx.Attributes;
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public sealed class CommandOptionAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes an instance of <see cref="CommandOptionAttribute" />.
|
||||
/// </summary>
|
||||
private CommandOptionAttribute(string? name, char? shortName)
|
||||
{
|
||||
Name = name;
|
||||
ShortName = shortName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes an instance of <see cref="CommandOptionAttribute" />.
|
||||
/// </summary>
|
||||
public CommandOptionAttribute(string name, char shortName)
|
||||
: this(name, (char?)shortName) { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes an instance of <see cref="CommandOptionAttribute" />.
|
||||
/// </summary>
|
||||
public CommandOptionAttribute(string name)
|
||||
: this(name, null) { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes an instance of <see cref="CommandOptionAttribute" />.
|
||||
/// </summary>
|
||||
public CommandOptionAttribute(char shortName)
|
||||
: this(null, (char?)shortName) { }
|
||||
|
||||
/// <summary>
|
||||
/// Option name.
|
||||
/// </summary>
|
||||
@@ -67,31 +94,4 @@ public sealed class CommandOptionAttribute : Attribute
|
||||
/// Validators must derive from <see cref="BindingValidator{T}" />.
|
||||
/// </remarks>
|
||||
public Type[] Validators { get; set; } = Array.Empty<Type>();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes an instance of <see cref="CommandOptionAttribute" />.
|
||||
/// </summary>
|
||||
private CommandOptionAttribute(string? name, char? shortName)
|
||||
{
|
||||
Name = name;
|
||||
ShortName = shortName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes an instance of <see cref="CommandOptionAttribute" />.
|
||||
/// </summary>
|
||||
public CommandOptionAttribute(string name, char shortName)
|
||||
: this(name, (char?)shortName) { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes an instance of <see cref="CommandOptionAttribute" />.
|
||||
/// </summary>
|
||||
public CommandOptionAttribute(string name)
|
||||
: this(name, null) { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes an instance of <see cref="CommandOptionAttribute" />.
|
||||
/// </summary>
|
||||
public CommandOptionAttribute(char shortName)
|
||||
: this(null, (char?)shortName) { }
|
||||
}
|
||||
|
||||
@@ -11,8 +11,8 @@ namespace CliFx.Infrastructure;
|
||||
/// </summary>
|
||||
// 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)
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes an instance of <see cref="ConsoleReader" />.
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -12,9 +12,18 @@ namespace CliFx.Infrastructure;
|
||||
/// </summary>
|
||||
// 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
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes an instance of <see cref="ConsoleWriter" />.
|
||||
/// </summary>
|
||||
public ConsoleWriter(IConsole console, Stream stream, Encoding encoding)
|
||||
: base(Stream.Synchronized(stream), encoding.WithoutPreamble(), 256)
|
||||
{
|
||||
Console = console;
|
||||
AutoFlush = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes an instance of <see cref="ConsoleWriter" />.
|
||||
/// </summary>
|
||||
@@ -24,7 +33,7 @@ public partial class ConsoleWriter(IConsole console, Stream stream, Encoding enc
|
||||
/// <summary>
|
||||
/// Console that owns this stream.
|
||||
/// </summary>
|
||||
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 };
|
||||
}
|
||||
|
||||
@@ -6,15 +6,24 @@ using System.Threading;
|
||||
namespace CliFx.Infrastructure;
|
||||
|
||||
/// <summary>
|
||||
/// Implementation of <see cref="IConsole" /> 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 <see cref="IConsole" /> 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.
|
||||
/// </summary>
|
||||
public class FakeConsole : IConsole, IDisposable
|
||||
{
|
||||
private readonly CancellationTokenSource _cancellationTokenSource = new();
|
||||
private readonly ConcurrentQueue<ConsoleKeyInfo> _keys = new();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes an instance of <see cref="FakeConsole" />.
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ConsoleReader Input { get; }
|
||||
|
||||
@@ -52,14 +61,9 @@ public class FakeConsole : IConsole, IDisposable
|
||||
public int CursorTop { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes an instance of <see cref="FakeConsole" />.
|
||||
/// Enqueues a simulated key press, which can then be read by calling <see cref="ReadKey" />.
|
||||
/// </summary>
|
||||
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);
|
||||
|
||||
/// <inheritdoc />
|
||||
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."
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Enqueues a simulated key press, which can then be read by calling <see cref="ReadKey" />.
|
||||
/// </summary>
|
||||
public void EnqueueKey(ConsoleKeyInfo key) => _keys.Enqueue(key);
|
||||
|
||||
/// <inheritdoc />
|
||||
public void ResetColor()
|
||||
{
|
||||
@@ -85,11 +84,8 @@ public class FakeConsole : IConsole, IDisposable
|
||||
/// <inheritdoc />
|
||||
public void Clear() { }
|
||||
|
||||
/// <inheritdoc />
|
||||
public CancellationToken RegisterCancellationHandler() => _cancellationTokenSource.Token;
|
||||
|
||||
/// <summary>
|
||||
/// Sends a cancellation signal to the currently executing command.
|
||||
/// Simulates a cancellation request.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If the command is not cancellation-aware (i.e. it doesn't call <see cref="IConsole.RegisterCancellationHandler" />),
|
||||
@@ -108,6 +104,9 @@ public class FakeConsole : IConsole, IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public CancellationToken RegisterCancellationHandler() => _cancellationTokenSource.Token;
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual void Dispose() => _cancellationTokenSource.Dispose();
|
||||
}
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
namespace CliFx.Infrastructure;
|
||||
|
||||
/// <summary>
|
||||
/// Implementation of <see cref="IConsole" /> 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 <see cref="IConsole" /> 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.
|
||||
/// </summary>
|
||||
public class FakeInMemoryConsole : FakeConsole
|
||||
{
|
||||
|
||||
@@ -5,47 +5,47 @@ using CliFx.Utils;
|
||||
namespace CliFx.Infrastructure;
|
||||
|
||||
/// <summary>
|
||||
/// Abstraction for the console layer.
|
||||
/// Abstraction for interacting with the console layer.
|
||||
/// </summary>
|
||||
public interface IConsole
|
||||
{
|
||||
/// <summary>
|
||||
/// Input stream (stdin).
|
||||
/// Console's standard input stream.
|
||||
/// </summary>
|
||||
ConsoleReader Input { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value that indicates whether input has been redirected from the standard input stream.
|
||||
/// Whether the input stream has been redirected.
|
||||
/// </summary>
|
||||
bool IsInputRedirected { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Output stream (stdout).
|
||||
/// Console's standard output stream.
|
||||
/// </summary>
|
||||
ConsoleWriter Output { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value that indicates whether output has been redirected from the standard output stream.
|
||||
/// Whether the output stream has been redirected.
|
||||
/// </summary>
|
||||
bool IsOutputRedirected { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Error stream (stderr).
|
||||
/// Console's standard error stream.
|
||||
/// </summary>
|
||||
ConsoleWriter Error { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value that indicates whether error output has been redirected from the standard error stream.
|
||||
/// Whether the error stream has been redirected.
|
||||
/// </summary>
|
||||
bool IsErrorRedirected { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the foreground color of the console
|
||||
/// Gets or sets the current foreground color of the console.
|
||||
/// </summary>
|
||||
ConsoleColor ForegroundColor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the background color of the console.
|
||||
/// Gets or sets the current background color of the console.
|
||||
/// </summary>
|
||||
ConsoleColor BackgroundColor { get; set; }
|
||||
|
||||
|
||||
@@ -10,6 +10,16 @@ public class SystemConsole : IConsole, IDisposable
|
||||
{
|
||||
private CancellationTokenSource? _cancellationTokenSource;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes an instance of <see cref="SystemConsole" />.
|
||||
/// </summary>
|
||||
public SystemConsole()
|
||||
{
|
||||
Input = new ConsoleReader(this, Console.OpenStandardInput());
|
||||
Output = new ConsoleWriter(this, Console.OpenStandardOutput());
|
||||
Error = new ConsoleWriter(this, Console.OpenStandardError());
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ConsoleReader Input { get; }
|
||||
|
||||
@@ -70,16 +80,6 @@ public class SystemConsole : IConsole, IDisposable
|
||||
set => Console.CursorTop = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes an instance of <see cref="SystemConsole" />.
|
||||
/// </summary>
|
||||
public SystemConsole()
|
||||
{
|
||||
Input = ConsoleReader.Create(this, Console.OpenStandardInput());
|
||||
Output = ConsoleWriter.Create(this, Console.OpenStandardOutput());
|
||||
Error = ConsoleWriter.Create(this, Console.OpenStandardError());
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ConsoleKeyInfo ReadKey(bool intercept = false) => Console.ReadKey(intercept);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user