diff --git a/.editorconfig b/.editorconfig index 6399c11..d338199 100644 --- a/.editorconfig +++ b/.editorconfig @@ -30,6 +30,9 @@ trim_trailing_whitespace = false end_of_line = lf [*.cs] +# Prefer file scoped namespace declarations +csharp_style_namespace_declarations = file_scoped:warning + # Sort using and Import directives with System.* appearing first dotnet_sort_system_directives_first = true dotnet_separate_import_directive_groups = false diff --git a/examples/Cli/Delegates/BarSettings.cs b/examples/Cli/Delegates/BarSettings.cs index 61dc9f7..aeab79b 100644 --- a/examples/Cli/Delegates/BarSettings.cs +++ b/examples/Cli/Delegates/BarSettings.cs @@ -1,16 +1,15 @@ using System.ComponentModel; using Spectre.Console.Cli; -namespace Spectre.Console.Examples +namespace Spectre.Console.Examples; + +public static partial class Program { - public static partial class Program + public sealed class BarSettings : CommandSettings { - public sealed class BarSettings : CommandSettings - { - [CommandOption("--count")] - [Description("The number of bars to print")] - [DefaultValue(1)] - public int Count { get; set; } - } + [CommandOption("--count")] + [Description("The number of bars to print")] + [DefaultValue(1)] + public int Count { get; set; } } } diff --git a/examples/Cli/Delegates/Program.cs b/examples/Cli/Delegates/Program.cs index 2523ddb..0dcbfe4 100644 --- a/examples/Cli/Delegates/Program.cs +++ b/examples/Cli/Delegates/Program.cs @@ -1,38 +1,37 @@ using Spectre.Console.Cli; -namespace Spectre.Console.Examples +namespace Spectre.Console.Examples; + +public static partial class Program { - public static partial class Program + public static int Main(string[] args) { - public static int Main(string[] args) + var app = new CommandApp(); + app.Configure(config => { - var app = new CommandApp(); - app.Configure(config => - { - config.AddDelegate("foo", Foo) - .WithDescription("Foos the bars"); + config.AddDelegate("foo", Foo) + .WithDescription("Foos the bars"); - config.AddDelegate("bar", Bar) - .WithDescription("Bars the foos"); ; - }); + config.AddDelegate("bar", Bar) + .WithDescription("Bars the foos"); ; + }); - return app.Run(args); + return app.Run(args); + } + + private static int Foo(CommandContext context) + { + AnsiConsole.WriteLine("Foo"); + return 0; + } + + private static int Bar(CommandContext context, BarSettings settings) + { + for (var index = 0; index < settings.Count; index++) + { + AnsiConsole.WriteLine("Bar"); } - private static int Foo(CommandContext context) - { - AnsiConsole.WriteLine("Foo"); - return 0; - } - - private static int Bar(CommandContext context, BarSettings settings) - { - for (var index = 0; index < settings.Count; index++) - { - AnsiConsole.WriteLine("Bar"); - } - - return 0; - } + return 0; } } diff --git a/examples/Cli/Demo/Commands/Add/AddPackageCommand.cs b/examples/Cli/Demo/Commands/Add/AddPackageCommand.cs index 16fec31..cf31e85 100644 --- a/examples/Cli/Demo/Commands/Add/AddPackageCommand.cs +++ b/examples/Cli/Demo/Commands/Add/AddPackageCommand.cs @@ -2,46 +2,45 @@ using System.ComponentModel; using Demo.Utilities; using Spectre.Console.Cli; -namespace Demo.Commands +namespace Demo.Commands; + +[Description("Add a NuGet package reference to the project.")] +public sealed class AddPackageCommand : Command { - [Description("Add a NuGet package reference to the project.")] - public sealed class AddPackageCommand : Command + public sealed class Settings : AddSettings { - public sealed class Settings : AddSettings - { - [CommandArgument(0, "")] - [Description("The package reference to add.")] - public string PackageName { get; set; } + [CommandArgument(0, "")] + [Description("The package reference to add.")] + public string PackageName { get; set; } - [CommandOption("-v|--version ")] - [Description("The version of the package to add.")] - public string Version { get; set; } + [CommandOption("-v|--version ")] + [Description("The version of the package to add.")] + public string Version { get; set; } - [CommandOption("-f|--framework ")] - [Description("Add the reference only when targeting a specific framework.")] - public string Framework { get; set; } + [CommandOption("-f|--framework ")] + [Description("Add the reference only when targeting a specific framework.")] + public string Framework { get; set; } - [CommandOption("--no-restore")] - [Description("Add the reference without performing restore preview and compatibility check.")] - public bool NoRestore { get; set; } + [CommandOption("--no-restore")] + [Description("Add the reference without performing restore preview and compatibility check.")] + public bool NoRestore { get; set; } - [CommandOption("--source ")] - [Description("The NuGet package source to use during the restore.")] - public string Source { get; set; } + [CommandOption("--source ")] + [Description("The NuGet package source to use during the restore.")] + public string Source { get; set; } - [CommandOption("--package-directory ")] - [Description("The directory to restore packages to.")] - public string PackageDirectory { get; set; } + [CommandOption("--package-directory ")] + [Description("The directory to restore packages to.")] + public string PackageDirectory { get; set; } - [CommandOption("--interactive")] - [Description("Allows the command to stop and wait for user input or action (for example to complete authentication).")] - public bool Interactive { get; set; } - } + [CommandOption("--interactive")] + [Description("Allows the command to stop and wait for user input or action (for example to complete authentication).")] + public bool Interactive { get; set; } + } - public override int Execute(CommandContext context, Settings settings) - { - SettingsDumper.Dump(settings); - return 0; - } + public override int Execute(CommandContext context, Settings settings) + { + SettingsDumper.Dump(settings); + return 0; } } diff --git a/examples/Cli/Demo/Commands/Add/AddReferenceCommand.cs b/examples/Cli/Demo/Commands/Add/AddReferenceCommand.cs index 6229743..be5111e 100644 --- a/examples/Cli/Demo/Commands/Add/AddReferenceCommand.cs +++ b/examples/Cli/Demo/Commands/Add/AddReferenceCommand.cs @@ -2,29 +2,28 @@ using System.ComponentModel; using Demo.Utilities; using Spectre.Console.Cli; -namespace Demo.Commands +namespace Demo.Commands; + +public sealed class AddReferenceCommand : Command { - public sealed class AddReferenceCommand : Command + public sealed class Settings : AddSettings { - public sealed class Settings : AddSettings - { - [CommandArgument(0, "")] - [Description("The package reference to add.")] - public string ProjectPath { get; set; } + [CommandArgument(0, "")] + [Description("The package reference to add.")] + public string ProjectPath { get; set; } - [CommandOption("-f|--framework ")] - [Description("Add the reference only when targeting a specific framework.")] - public string Framework { get; set; } + [CommandOption("-f|--framework ")] + [Description("Add the reference only when targeting a specific framework.")] + public string Framework { get; set; } - [CommandOption("--interactive")] - [Description("Allows the command to stop and wait for user input or action (for example to complete authentication).")] - public bool Interactive { get; set; } - } + [CommandOption("--interactive")] + [Description("Allows the command to stop and wait for user input or action (for example to complete authentication).")] + public bool Interactive { get; set; } + } - public override int Execute(CommandContext context, Settings settings) - { - SettingsDumper.Dump(settings); - return 0; - } + public override int Execute(CommandContext context, Settings settings) + { + SettingsDumper.Dump(settings); + return 0; } } diff --git a/examples/Cli/Demo/Commands/Add/AddSettings.cs b/examples/Cli/Demo/Commands/Add/AddSettings.cs index 95743ac..df07cd5 100644 --- a/examples/Cli/Demo/Commands/Add/AddSettings.cs +++ b/examples/Cli/Demo/Commands/Add/AddSettings.cs @@ -1,12 +1,11 @@ using System.ComponentModel; using Spectre.Console.Cli; -namespace Demo.Commands +namespace Demo.Commands; + +public abstract class AddSettings : CommandSettings { - public abstract class AddSettings : CommandSettings - { - [CommandArgument(0, "")] - [Description("The project file to operate on. If a file is not specified, the command will search the current directory for one.")] - public string Project { get; set; } - } + [CommandArgument(0, "")] + [Description("The project file to operate on. If a file is not specified, the command will search the current directory for one.")] + public string Project { get; set; } } diff --git a/examples/Cli/Demo/Commands/Run/RunCommand.cs b/examples/Cli/Demo/Commands/Run/RunCommand.cs index 772b572..94a0b5e 100644 --- a/examples/Cli/Demo/Commands/Run/RunCommand.cs +++ b/examples/Cli/Demo/Commands/Run/RunCommand.cs @@ -2,69 +2,68 @@ using System.ComponentModel; using Demo.Utilities; using Spectre.Console.Cli; -namespace Demo.Commands +namespace Demo.Commands; + +[Description("Build and run a .NET project output.")] +public sealed class RunCommand : Command { - [Description("Build and run a .NET project output.")] - public sealed class RunCommand : Command + public sealed class Settings : CommandSettings { - public sealed class Settings : CommandSettings - { - [CommandOption("-c|--configuration ")] - [Description("The configuration to run for. The default for most projects is '[grey]Debug[/]'.")] - [DefaultValue("Debug")] - public string Configuration { get; set; } + [CommandOption("-c|--configuration ")] + [Description("The configuration to run for. The default for most projects is '[grey]Debug[/]'.")] + [DefaultValue("Debug")] + public string Configuration { get; set; } - [CommandOption("-f|--framework ")] - [Description("The target framework to run for. The target framework must also be specified in the project file.")] - public string Framework { get; set; } + [CommandOption("-f|--framework ")] + [Description("The target framework to run for. The target framework must also be specified in the project file.")] + public string Framework { get; set; } - [CommandOption("-r|--runtime ")] - [Description("The target runtime to run for.")] - public string RuntimeIdentifier { get; set; } + [CommandOption("-r|--runtime ")] + [Description("The target runtime to run for.")] + public string RuntimeIdentifier { get; set; } - [CommandOption("-p|--project ")] - [Description("The path to the project file to run (defaults to the current directory if there is only one project).")] - public string ProjectPath { get; set; } + [CommandOption("-p|--project ")] + [Description("The path to the project file to run (defaults to the current directory if there is only one project).")] + public string ProjectPath { get; set; } - [CommandOption("--launch-profile ")] - [Description("The name of the launch profile (if any) to use when launching the application.")] - public string LaunchProfile { get; set; } + [CommandOption("--launch-profile ")] + [Description("The name of the launch profile (if any) to use when launching the application.")] + public string LaunchProfile { get; set; } - [CommandOption("--no-launch-profile")] - [Description("Do not attempt to use [grey]launchSettings.json[/] to configure the application.")] - public bool NoLaunchProfile { get; set; } + [CommandOption("--no-launch-profile")] + [Description("Do not attempt to use [grey]launchSettings.json[/] to configure the application.")] + public bool NoLaunchProfile { get; set; } - [CommandOption("--no-build")] - [Description("Do not build the project before running. Implies [grey]--no-restore[/].")] - public bool NoBuild { get; set; } + [CommandOption("--no-build")] + [Description("Do not build the project before running. Implies [grey]--no-restore[/].")] + public bool NoBuild { get; set; } - [CommandOption("--interactive")] - [Description("Allows the command to stop and wait for user input or action (for example to complete authentication).")] - public string Interactive { get; set; } + [CommandOption("--interactive")] + [Description("Allows the command to stop and wait for user input or action (for example to complete authentication).")] + public string Interactive { get; set; } - [CommandOption("--no-restore")] - [Description("Do not restore the project before building.")] - public bool NoRestore { get; set; } + [CommandOption("--no-restore")] + [Description("Do not restore the project before building.")] + public bool NoRestore { get; set; } - [CommandOption("--verbosity ")] - [Description("Set the MSBuild verbosity level. Allowed values are q[grey]uiet[/], m[grey]inimal[/], n[grey]ormal[/], d[grey]etailed[/], and diag[grey]nostic[/].")] - [TypeConverter(typeof(VerbosityConverter))] - [DefaultValue(Verbosity.Normal)] - public Verbosity Verbosity { get; set; } + [CommandOption("--verbosity ")] + [Description("Set the MSBuild verbosity level. Allowed values are q[grey]uiet[/], m[grey]inimal[/], n[grey]ormal[/], d[grey]etailed[/], and diag[grey]nostic[/].")] + [TypeConverter(typeof(VerbosityConverter))] + [DefaultValue(Verbosity.Normal)] + public Verbosity Verbosity { get; set; } - [CommandOption("--no-dependencies")] - [Description("Do not restore project-to-project references and only restore the specified project.")] - public bool NoDependencies { get; set; } + [CommandOption("--no-dependencies")] + [Description("Do not restore project-to-project references and only restore the specified project.")] + public bool NoDependencies { get; set; } - [CommandOption("--force")] - [Description("Force all dependencies to be resolved even if the last restore was successful. This is equivalent to deleting [grey]project.assets.json[/].")] - public bool Force { get; set; } - } + [CommandOption("--force")] + [Description("Force all dependencies to be resolved even if the last restore was successful. This is equivalent to deleting [grey]project.assets.json[/].")] + public bool Force { get; set; } + } - public override int Execute(CommandContext context, Settings settings) - { - SettingsDumper.Dump(settings); - return 0; - } + public override int Execute(CommandContext context, Settings settings) + { + SettingsDumper.Dump(settings); + return 0; } } diff --git a/examples/Cli/Demo/Commands/Serve/ServeCommand.cs b/examples/Cli/Demo/Commands/Serve/ServeCommand.cs index 49298c5..61ed767 100644 --- a/examples/Cli/Demo/Commands/Serve/ServeCommand.cs +++ b/examples/Cli/Demo/Commands/Serve/ServeCommand.cs @@ -3,39 +3,38 @@ using System.ComponentModel; using Demo.Utilities; using Spectre.Console.Cli; -namespace Demo.Commands +namespace Demo.Commands; + +[Description("Launches a web server in the current working directory and serves all files in it.")] +public sealed class ServeCommand : Command { - [Description("Launches a web server in the current working directory and serves all files in it.")] - public sealed class ServeCommand : Command + public sealed class Settings : CommandSettings { - public sealed class Settings : CommandSettings - { - [CommandOption("-p|--port ")] - [Description("Port to use. Defaults to [grey]8080[/]. Use [grey]0[/] for a dynamic port.")] - public int Port { get; set; } + [CommandOption("-p|--port ")] + [Description("Port to use. Defaults to [grey]8080[/]. Use [grey]0[/] for a dynamic port.")] + public int Port { get; set; } - [CommandOption("-o|--open-browser [BROWSER]")] - [Description("Open a web browser when the server starts. You can also specify which browser to use. If none is specified, the default one will be used.")] - public FlagValue OpenBrowser { get; set; } - } + [CommandOption("-o|--open-browser [BROWSER]")] + [Description("Open a web browser when the server starts. You can also specify which browser to use. If none is specified, the default one will be used.")] + public FlagValue OpenBrowser { get; set; } + } - public override int Execute(CommandContext context, Settings settings) + public override int Execute(CommandContext context, Settings settings) + { + if (settings.OpenBrowser.IsSet) { - if (settings.OpenBrowser.IsSet) + var browser = settings.OpenBrowser.Value; + if (browser != null) { - var browser = settings.OpenBrowser.Value; - if (browser != null) - { - Console.WriteLine($"Open in {browser}"); - } - else - { - Console.WriteLine($"Open in default browser."); - } + Console.WriteLine($"Open in {browser}"); + } + else + { + Console.WriteLine($"Open in default browser."); } - - SettingsDumper.Dump(settings); - return 0; } + + SettingsDumper.Dump(settings); + return 0; } } diff --git a/examples/Cli/Demo/Program.cs b/examples/Cli/Demo/Program.cs index e63fa04..56a1de3 100644 --- a/examples/Cli/Demo/Program.cs +++ b/examples/Cli/Demo/Program.cs @@ -1,37 +1,36 @@ using Demo.Commands; using Spectre.Console.Cli; -namespace Demo +namespace Demo; + +public static class Program { - public static class Program + public static int Main(string[] args) { - public static int Main(string[] args) + var app = new CommandApp(); + app.Configure(config => { - var app = new CommandApp(); - app.Configure(config => - { - config.SetApplicationName("fake-dotnet"); - config.ValidateExamples(); - config.AddExample(new[] { "run", "--no-build" }); + config.SetApplicationName("fake-dotnet"); + config.ValidateExamples(); + config.AddExample(new[] { "run", "--no-build" }); // Run config.AddCommand("run"); // Add config.AddBranch("add", add => - { - add.SetDescription("Add a package or reference to a .NET project"); - add.AddCommand("package"); - add.AddCommand("reference"); - }); + { + add.SetDescription("Add a package or reference to a .NET project"); + add.AddCommand("package"); + add.AddCommand("reference"); + }); // Serve config.AddCommand("serve") - .WithExample(new[] { "serve", "-o", "firefox" }) - .WithExample(new[] { "serve", "--port", "80", "-o", "firefox" }); - }); + .WithExample(new[] { "serve", "-o", "firefox" }) + .WithExample(new[] { "serve", "--port", "80", "-o", "firefox" }); + }); - return app.Run(args); - } + return app.Run(args); } } diff --git a/examples/Cli/Demo/Utilities/SettingsDumper.cs b/examples/Cli/Demo/Utilities/SettingsDumper.cs index 3533372..4445927 100644 --- a/examples/Cli/Demo/Utilities/SettingsDumper.cs +++ b/examples/Cli/Demo/Utilities/SettingsDumper.cs @@ -1,29 +1,28 @@ using Spectre.Console; using Spectre.Console.Cli; -namespace Demo.Utilities +namespace Demo.Utilities; + +public static class SettingsDumper { - public static class SettingsDumper + public static void Dump(CommandSettings settings) { - public static void Dump(CommandSettings settings) + var table = new Table().RoundedBorder(); + table.AddColumn("[grey]Name[/]"); + table.AddColumn("[grey]Value[/]"); + + var properties = settings.GetType().GetProperties(); + foreach (var property in properties) { - var table = new Table().RoundedBorder(); - table.AddColumn("[grey]Name[/]"); - table.AddColumn("[grey]Value[/]"); + var value = property.GetValue(settings) + ?.ToString() + ?.Replace("[", "[["); - var properties = settings.GetType().GetProperties(); - foreach (var property in properties) - { - var value = property.GetValue(settings) - ?.ToString() - ?.Replace("[", "[["); - - table.AddRow( - property.Name, - value ?? "[grey]null[/]"); - } - - AnsiConsole.Write(table); + table.AddRow( + property.Name, + value ?? "[grey]null[/]"); } + + AnsiConsole.Write(table); } } diff --git a/examples/Cli/Demo/Verbosity.cs b/examples/Cli/Demo/Verbosity.cs index 498a8c8..84fc3b4 100644 --- a/examples/Cli/Demo/Verbosity.cs +++ b/examples/Cli/Demo/Verbosity.cs @@ -3,24 +3,24 @@ using System.Collections.Generic; using System.ComponentModel; using System.Globalization; -namespace Demo +namespace Demo; + +public enum Verbosity { - public enum Verbosity - { - Quiet, - Minimal, - Normal, - Detailed, - Diagnostic - } + Quiet, + Minimal, + Normal, + Detailed, + Diagnostic +} - public sealed class VerbosityConverter : TypeConverter - { - private readonly Dictionary _lookup; +public sealed class VerbosityConverter : TypeConverter +{ + private readonly Dictionary _lookup; - public VerbosityConverter() - { - _lookup = new Dictionary(StringComparer.OrdinalIgnoreCase) + public VerbosityConverter() + { + _lookup = new Dictionary(StringComparer.OrdinalIgnoreCase) { { "q", Verbosity.Quiet }, { "quiet", Verbosity.Quiet }, @@ -33,22 +33,21 @@ namespace Demo { "diag", Verbosity.Diagnostic }, { "diagnostic", Verbosity.Diagnostic } }; - } + } - public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + { + if (value is string stringValue) { - if (value is string stringValue) + var result = _lookup.TryGetValue(stringValue, out var verbosity); + if (!result) { - var result = _lookup.TryGetValue(stringValue, out var verbosity); - if (!result) - { - const string format = "The value '{0}' is not a valid verbosity."; - var message = string.Format(CultureInfo.InvariantCulture, format, value); - throw new InvalidOperationException(message); - } - return verbosity; + const string format = "The value '{0}' is not a valid verbosity."; + var message = string.Format(CultureInfo.InvariantCulture, format, value); + throw new InvalidOperationException(message); } - throw new NotSupportedException("Can't convert value to verbosity."); + return verbosity; } + throw new NotSupportedException("Can't convert value to verbosity."); } } diff --git a/examples/Cli/Dynamic/MyCommand.cs b/examples/Cli/Dynamic/MyCommand.cs index 220a6b1..a35908e 100644 --- a/examples/Cli/Dynamic/MyCommand.cs +++ b/examples/Cli/Dynamic/MyCommand.cs @@ -1,20 +1,19 @@ using System; using Spectre.Console.Cli; -namespace Spectre.Console.Examples -{ - public sealed class MyCommand : Command - { - public override int Execute(CommandContext context) - { - if (!(context.Data is int data)) - { - throw new InvalidOperationException("Command has no associated data."); - - } +namespace Spectre.Console.Examples; + +public sealed class MyCommand : Command +{ + public override int Execute(CommandContext context) + { + if (!(context.Data is int data)) + { + throw new InvalidOperationException("Command has no associated data."); - AnsiConsole.WriteLine("Value = {0}", data); - return 0; } + + AnsiConsole.WriteLine("Value = {0}", data); + return 0; } } diff --git a/examples/Cli/Dynamic/Program.cs b/examples/Cli/Dynamic/Program.cs index b90e53c..37a9d0e 100644 --- a/examples/Cli/Dynamic/Program.cs +++ b/examples/Cli/Dynamic/Program.cs @@ -1,24 +1,23 @@ using System.Linq; using Spectre.Console.Cli; -namespace Spectre.Console.Examples -{ - public static class Program - { - public static int Main(string[] args) - { - var app = new CommandApp(); - app.Configure(config => - { - foreach(var index in Enumerable.Range(1, 10)) - { - config.AddCommand($"c{index}") - .WithDescription($"Prints the number {index}") - .WithData(index); - } - }); +namespace Spectre.Console.Examples; - return app.Run(args); - } +public static class Program +{ + public static int Main(string[] args) + { + var app = new CommandApp(); + app.Configure(config => + { + foreach (var index in Enumerable.Range(1, 10)) + { + config.AddCommand($"c{index}") + .WithDescription($"Prints the number {index}") + .WithData(index); + } + }); + + return app.Run(args); } } diff --git a/examples/Cli/Injection/Commands/DefaultCommand.cs b/examples/Cli/Injection/Commands/DefaultCommand.cs index fe2e282..1b1c410 100644 --- a/examples/Cli/Injection/Commands/DefaultCommand.cs +++ b/examples/Cli/Injection/Commands/DefaultCommand.cs @@ -2,29 +2,28 @@ using System; using System.ComponentModel; using Spectre.Console.Cli; -namespace Spectre.Console.Examples +namespace Spectre.Console.Examples; + +public sealed class DefaultCommand : Command { - public sealed class DefaultCommand : Command + private readonly IGreeter _greeter; + + public sealed class Settings : CommandSettings { - private readonly IGreeter _greeter; + [CommandOption("-n|--name ")] + [Description("The person or thing to greet.")] + [DefaultValue("World")] + public string Name { get; set; } + } - public sealed class Settings : CommandSettings - { - [CommandOption("-n|--name ")] - [Description("The person or thing to greet.")] - [DefaultValue("World")] - public string Name { get; set; } - } + public DefaultCommand(IGreeter greeter) + { + _greeter = greeter ?? throw new ArgumentNullException(nameof(greeter)); + } - public DefaultCommand(IGreeter greeter) - { - _greeter = greeter ?? throw new ArgumentNullException(nameof(greeter)); - } - - public override int Execute(CommandContext context, Settings settings) - { - _greeter.Greet(settings.Name); - return 0; - } + public override int Execute(CommandContext context, Settings settings) + { + _greeter.Greet(settings.Name); + return 0; } } diff --git a/examples/Cli/Injection/IGreeter.cs b/examples/Cli/Injection/IGreeter.cs index be7d888..1d72fad 100644 --- a/examples/Cli/Injection/IGreeter.cs +++ b/examples/Cli/Injection/IGreeter.cs @@ -1,15 +1,14 @@ -namespace Spectre.Console.Examples -{ - public interface IGreeter - { - void Greet(string name); - } +namespace Spectre.Console.Examples; - public sealed class HelloWorldGreeter : IGreeter +public interface IGreeter +{ + void Greet(string name); +} + +public sealed class HelloWorldGreeter : IGreeter +{ + public void Greet(string name) { - public void Greet(string name) - { - AnsiConsole.WriteLine($"Hello {name}!"); - } + AnsiConsole.WriteLine($"Hello {name}!"); } } diff --git a/examples/Cli/Injection/Infrastructure/TypeRegistrar.cs b/examples/Cli/Injection/Infrastructure/TypeRegistrar.cs index ce9b364..73ed8b7 100644 --- a/examples/Cli/Injection/Infrastructure/TypeRegistrar.cs +++ b/examples/Cli/Injection/Infrastructure/TypeRegistrar.cs @@ -2,40 +2,39 @@ using System; using Microsoft.Extensions.DependencyInjection; using Spectre.Console.Cli; -namespace Spectre.Console.Examples +namespace Spectre.Console.Examples; + +public sealed class TypeRegistrar : ITypeRegistrar { - public sealed class TypeRegistrar : ITypeRegistrar + private readonly IServiceCollection _builder; + + public TypeRegistrar(IServiceCollection builder) { - private readonly IServiceCollection _builder; + _builder = builder; + } - public TypeRegistrar(IServiceCollection builder) + public ITypeResolver Build() + { + return new TypeResolver(_builder.BuildServiceProvider()); + } + + public void Register(Type service, Type implementation) + { + _builder.AddSingleton(service, implementation); + } + + public void RegisterInstance(Type service, object implementation) + { + _builder.AddSingleton(service, implementation); + } + + public void RegisterLazy(Type service, Func func) + { + if (func is null) { - _builder = builder; + throw new ArgumentNullException(nameof(func)); } - public ITypeResolver Build() - { - return new TypeResolver(_builder.BuildServiceProvider()); - } - - public void Register(Type service, Type implementation) - { - _builder.AddSingleton(service, implementation); - } - - public void RegisterInstance(Type service, object implementation) - { - _builder.AddSingleton(service, implementation); - } - - public void RegisterLazy(Type service, Func func) - { - if (func is null) - { - throw new ArgumentNullException(nameof(func)); - } - - _builder.AddSingleton(service, (provider) => func()); - } + _builder.AddSingleton(service, (provider) => func()); } } diff --git a/examples/Cli/Injection/Infrastructure/TypeResolver.cs b/examples/Cli/Injection/Infrastructure/TypeResolver.cs index 252e484..c897319 100644 --- a/examples/Cli/Injection/Infrastructure/TypeResolver.cs +++ b/examples/Cli/Injection/Infrastructure/TypeResolver.cs @@ -2,33 +2,32 @@ using System; using Microsoft.Extensions.DependencyInjection; using Spectre.Console.Cli; -namespace Spectre.Console.Examples +namespace Spectre.Console.Examples; + +public sealed class TypeResolver : ITypeResolver, IDisposable { - public sealed class TypeResolver : ITypeResolver, IDisposable + private readonly IServiceProvider _provider; + + public TypeResolver(IServiceProvider provider) { - private readonly IServiceProvider _provider; + _provider = provider ?? throw new ArgumentNullException(nameof(provider)); + } - public TypeResolver(IServiceProvider provider) + public object Resolve(Type type) + { + if (type == null) { - _provider = provider ?? throw new ArgumentNullException(nameof(provider)); + return null; } - public object Resolve(Type type) - { - if (type == null) - { - return null; - } + return _provider.GetService(type); + } - return _provider.GetService(type); - } - - public void Dispose() + public void Dispose() + { + if (_provider is IDisposable disposable) { - if (_provider is IDisposable disposable) - { - disposable.Dispose(); - } + disposable.Dispose(); } } } diff --git a/examples/Cli/Injection/Program.cs b/examples/Cli/Injection/Program.cs index 8ebaa0c..7097cc4 100644 --- a/examples/Cli/Injection/Program.cs +++ b/examples/Cli/Injection/Program.cs @@ -1,22 +1,21 @@ using Microsoft.Extensions.DependencyInjection; using Spectre.Console.Cli; -namespace Spectre.Console.Examples -{ - public class Program - { - public static int Main(string[] args) - { - // Create a type registrar and register any dependencies. - // A type registrar is an adapter for a DI framework. - var registrations = new ServiceCollection(); - registrations.AddSingleton(); - var registrar = new TypeRegistrar(registrations); +namespace Spectre.Console.Examples; - // Create a new command app with the registrar - // and run it with the provided arguments. - var app = new CommandApp(registrar); - return app.Run(args); - } +public class Program +{ + public static int Main(string[] args) + { + // Create a type registrar and register any dependencies. + // A type registrar is an adapter for a DI framework. + var registrations = new ServiceCollection(); + registrations.AddSingleton(); + var registrar = new TypeRegistrar(registrations); + + // Create a new command app with the registrar + // and run it with the provided arguments. + var app = new CommandApp(registrar); + return app.Run(args); } } diff --git a/examples/Cli/Logging/Commands/HelloCommand.cs b/examples/Cli/Logging/Commands/HelloCommand.cs index 2bbff0c..032d92b 100644 --- a/examples/Cli/Logging/Commands/HelloCommand.cs +++ b/examples/Cli/Logging/Commands/HelloCommand.cs @@ -1,34 +1,33 @@ using Microsoft.Extensions.Logging; using Spectre.Console.Cli; -namespace Spectre.Console.Examples +namespace Spectre.Console.Examples; + +public class HelloCommand : Command { - public class HelloCommand : Command + private ILogger _logger; + private IAnsiConsole _console; + + public HelloCommand(IAnsiConsole console, ILogger logger) { - private ILogger _logger; - private IAnsiConsole _console; - - public HelloCommand(IAnsiConsole console, ILogger logger) - { - _console = console; - _logger = logger; - _logger.LogDebug("{0} initialized", nameof(HelloCommand)); - } - - public class Settings : LogCommandSettings - { - [CommandArgument(0, "[Name]")] - public string Name { get; set; } - } - - - public override int Execute(CommandContext context, Settings settings) - { - _logger.LogInformation("Starting my command"); - AnsiConsole.MarkupLine($"Hello, [blue]{settings.Name}[/]"); - _logger.LogInformation("Completed my command"); - - return 0; - } + _console = console; + _logger = logger; + _logger.LogDebug("{0} initialized", nameof(HelloCommand)); } -} \ No newline at end of file + + public class Settings : LogCommandSettings + { + [CommandArgument(0, "[Name]")] + public string Name { get; set; } + } + + + public override int Execute(CommandContext context, Settings settings) + { + _logger.LogInformation("Starting my command"); + AnsiConsole.MarkupLine($"Hello, [blue]{settings.Name}[/]"); + _logger.LogInformation("Completed my command"); + + return 0; + } +} diff --git a/examples/Cli/Logging/Commands/LogCommandSettings.cs b/examples/Cli/Logging/Commands/LogCommandSettings.cs index da47b56..00d3113 100644 --- a/examples/Cli/Logging/Commands/LogCommandSettings.cs +++ b/examples/Cli/Logging/Commands/LogCommandSettings.cs @@ -5,28 +5,28 @@ using System.Globalization; using Serilog.Events; using Spectre.Console.Cli; -namespace Spectre.Console.Examples +namespace Spectre.Console.Examples; + +public class LogCommandSettings : CommandSettings { - public class LogCommandSettings : CommandSettings + [CommandOption("--logFile")] + [Description("Path and file name for logging")] + public string LogFile { get; set; } + + [CommandOption("--logLevel")] + [Description("Minimum level for logging")] + [TypeConverter(typeof(VerbosityConverter))] + [DefaultValue(LogEventLevel.Information)] + public LogEventLevel LogLevel { get; set; } +} + +public sealed class VerbosityConverter : TypeConverter +{ + private readonly Dictionary _lookup; + + public VerbosityConverter() { - [CommandOption("--logFile")] - [Description("Path and file name for logging")] - public string LogFile { get; set; } - - [CommandOption("--logLevel")] - [Description("Minimum level for logging")] - [TypeConverter(typeof(VerbosityConverter))] - [DefaultValue(LogEventLevel.Information)] - public LogEventLevel LogLevel { get; set; } - } - - public sealed class VerbosityConverter : TypeConverter - { - private readonly Dictionary _lookup; - - public VerbosityConverter() - { - _lookup = new Dictionary(StringComparer.OrdinalIgnoreCase) + _lookup = new Dictionary(StringComparer.OrdinalIgnoreCase) { {"d", LogEventLevel.Debug}, {"v", LogEventLevel.Verbose}, @@ -35,22 +35,21 @@ namespace Spectre.Console.Examples {"e", LogEventLevel.Error}, {"f", LogEventLevel.Fatal} }; - } - - public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) - { - if (value is string stringValue) - { - var result = _lookup.TryGetValue(stringValue, out var verbosity); - if (!result) - { - const string format = "The value '{0}' is not a valid verbosity."; - var message = string.Format(CultureInfo.InvariantCulture, format, value); - throw new InvalidOperationException(message); - } - return verbosity; - } - throw new NotSupportedException("Can't convert value to verbosity."); - } } -} \ No newline at end of file + + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + { + if (value is string stringValue) + { + var result = _lookup.TryGetValue(stringValue, out var verbosity); + if (!result) + { + const string format = "The value '{0}' is not a valid verbosity."; + var message = string.Format(CultureInfo.InvariantCulture, format, value); + throw new InvalidOperationException(message); + } + return verbosity; + } + throw new NotSupportedException("Can't convert value to verbosity."); + } +} diff --git a/examples/Cli/Logging/Infrastructure/LogInterceptor.cs b/examples/Cli/Logging/Infrastructure/LogInterceptor.cs index 31adaff..70ce7af 100644 --- a/examples/Cli/Logging/Infrastructure/LogInterceptor.cs +++ b/examples/Cli/Logging/Infrastructure/LogInterceptor.cs @@ -1,19 +1,18 @@ using Serilog.Core; using Spectre.Console.Cli; -namespace Spectre.Console.Examples -{ - public class LogInterceptor : ICommandInterceptor - { - public static readonly LoggingLevelSwitch LogLevel = new(); +namespace Spectre.Console.Examples; - public void Intercept(CommandContext context, CommandSettings settings) +public class LogInterceptor : ICommandInterceptor +{ + public static readonly LoggingLevelSwitch LogLevel = new(); + + public void Intercept(CommandContext context, CommandSettings settings) + { + if (settings is LogCommandSettings logSettings) { - if (settings is LogCommandSettings logSettings) - { - LoggingEnricher.Path = logSettings.LogFile ?? "application.log"; - LogLevel.MinimumLevel = logSettings.LogLevel; - } + LoggingEnricher.Path = logSettings.LogFile ?? "application.log"; + LogLevel.MinimumLevel = logSettings.LogLevel; } } -} \ No newline at end of file +} diff --git a/examples/Cli/Logging/Infrastructure/LoggingEnricher.cs b/examples/Cli/Logging/Infrastructure/LoggingEnricher.cs index e9e41e2..2b41e16 100644 --- a/examples/Cli/Logging/Infrastructure/LoggingEnricher.cs +++ b/examples/Cli/Logging/Infrastructure/LoggingEnricher.cs @@ -1,38 +1,37 @@ using Serilog.Core; using Serilog.Events; -namespace Spectre.Console.Examples +namespace Spectre.Console.Examples; + +internal class LoggingEnricher : ILogEventEnricher { - internal class LoggingEnricher : ILogEventEnricher + private string _cachedLogFilePath; + private LogEventProperty _cachedLogFilePathProperty; + + // this path and level will be set by the LogInterceptor.cs after parsing the settings + public static string Path = string.Empty; + + public const string LogFilePathPropertyName = "LogFilePath"; + + public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) { - private string _cachedLogFilePath; - private LogEventProperty _cachedLogFilePathProperty; + // the settings might not have a path or we might not be within a command in which case + // we won't have the setting so a default value for the log file will be required + LogEventProperty logFilePathProperty; - // this path and level will be set by the LogInterceptor.cs after parsing the settings - public static string Path = string.Empty; - - public const string LogFilePathPropertyName = "LogFilePath"; - - public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) + if (_cachedLogFilePathProperty != null && Path.Equals(_cachedLogFilePath)) { - // the settings might not have a path or we might not be within a command in which case - // we won't have the setting so a default value for the log file will be required - LogEventProperty logFilePathProperty; - - if (_cachedLogFilePathProperty != null && Path.Equals(_cachedLogFilePath)) - { - // Path hasn't changed, so let's use the cached property - logFilePathProperty = _cachedLogFilePathProperty; - } - else - { - // We've got a new path for the log. Let's create a new property - // and cache it for future log events to use - _cachedLogFilePath = Path; - _cachedLogFilePathProperty = logFilePathProperty = propertyFactory.CreateProperty(LogFilePathPropertyName, Path); - } - - logEvent.AddPropertyIfAbsent(logFilePathProperty); + // Path hasn't changed, so let's use the cached property + logFilePathProperty = _cachedLogFilePathProperty; } + else + { + // We've got a new path for the log. Let's create a new property + // and cache it for future log events to use + _cachedLogFilePath = Path; + _cachedLogFilePathProperty = logFilePathProperty = propertyFactory.CreateProperty(LogFilePathPropertyName, Path); + } + + logEvent.AddPropertyIfAbsent(logFilePathProperty); } -} \ No newline at end of file +} diff --git a/examples/Cli/Logging/Infrastructure/TypeRegistrar.cs b/examples/Cli/Logging/Infrastructure/TypeRegistrar.cs index bd7692f..8f0af7f 100644 --- a/examples/Cli/Logging/Infrastructure/TypeRegistrar.cs +++ b/examples/Cli/Logging/Infrastructure/TypeRegistrar.cs @@ -2,40 +2,39 @@ using System; using Microsoft.Extensions.DependencyInjection; using Spectre.Console.Cli; -namespace Spectre.Console.Examples +namespace Spectre.Console.Examples; + +public sealed class TypeRegistrar : ITypeRegistrar { - public sealed class TypeRegistrar : ITypeRegistrar + private readonly IServiceCollection _builder; + + public TypeRegistrar(IServiceCollection builder) { - private readonly IServiceCollection _builder; - - public TypeRegistrar(IServiceCollection builder) - { - _builder = builder; - } - - public ITypeResolver Build() - { - return new TypeResolver(_builder.BuildServiceProvider()); - } - - public void Register(Type service, Type implementation) - { - _builder.AddSingleton(service, implementation); - } - - public void RegisterInstance(Type service, object implementation) - { - _builder.AddSingleton(service, implementation); - } - - public void RegisterLazy(Type service, Func func) - { - if (func is null) - { - throw new ArgumentNullException(nameof(func)); - } - - _builder.AddSingleton(service, _ => func()); - } + _builder = builder; } -} \ No newline at end of file + + public ITypeResolver Build() + { + return new TypeResolver(_builder.BuildServiceProvider()); + } + + public void Register(Type service, Type implementation) + { + _builder.AddSingleton(service, implementation); + } + + public void RegisterInstance(Type service, object implementation) + { + _builder.AddSingleton(service, implementation); + } + + public void RegisterLazy(Type service, Func func) + { + if (func is null) + { + throw new ArgumentNullException(nameof(func)); + } + + _builder.AddSingleton(service, _ => func()); + } +} diff --git a/examples/Cli/Logging/Infrastructure/TypeResolver.cs b/examples/Cli/Logging/Infrastructure/TypeResolver.cs index e449c85..888bc07 100644 --- a/examples/Cli/Logging/Infrastructure/TypeResolver.cs +++ b/examples/Cli/Logging/Infrastructure/TypeResolver.cs @@ -2,20 +2,19 @@ using System; using Microsoft.Extensions.DependencyInjection; using Spectre.Console.Cli; -namespace Spectre.Console.Examples +namespace Spectre.Console.Examples; + +public sealed class TypeResolver : ITypeResolver { - public sealed class TypeResolver : ITypeResolver + private readonly IServiceProvider _provider; + + public TypeResolver(IServiceProvider provider) { - private readonly IServiceProvider _provider; - - public TypeResolver(IServiceProvider provider) - { - _provider = provider ?? throw new ArgumentNullException(nameof(provider)); - } - - public object Resolve(Type type) - { - return _provider.GetRequiredService(type); - } + _provider = provider ?? throw new ArgumentNullException(nameof(provider)); } -} \ No newline at end of file + + public object Resolve(Type type) + { + return _provider.GetRequiredService(type); + } +} diff --git a/examples/Cli/Logging/Program.cs b/examples/Cli/Logging/Program.cs index cc05479..111f00b 100644 --- a/examples/Cli/Logging/Program.cs +++ b/examples/Cli/Logging/Program.cs @@ -12,42 +12,41 @@ using Spectre.Console.Cli; * Spectre.Console CommandInterceptor */ -namespace Spectre.Console.Examples +namespace Spectre.Console.Examples; + +public class Program { - public class Program + static int Main(string[] args) { - static int Main(string[] args) + // to retrieve the log file name, we must first parse the command settings + // this will require us to delay setting the file path for the file writer. + // With serilog we can use an enricher and Serilog.Sinks.Map to dynamically + // pull this setting. + var serviceCollection = new ServiceCollection() + .AddLogging(configure => + configure.AddSerilog(new LoggerConfiguration() + // log level will be dynamically be controlled by our log interceptor upon running + .MinimumLevel.ControlledBy(LogInterceptor.LogLevel) + // the log enricher will add a new property with the log file path from the settings + // that we can use to set the path dynamically + .Enrich.With() + // serilog.sinks.map will defer the configuration of the sink to be ondemand + // allowing us to look at the properties set by the enricher to set the path appropriately + .WriteTo.Map(LoggingEnricher.LogFilePathPropertyName, + (logFilePath, wt) => wt.File($"{logFilePath}"), 1) + .CreateLogger() + ) + ); + + var registrar = new TypeRegistrar(serviceCollection); + var app = new CommandApp(registrar); + + app.Configure(config => { - // to retrieve the log file name, we must first parse the command settings - // this will require us to delay setting the file path for the file writer. - // With serilog we can use an enricher and Serilog.Sinks.Map to dynamically - // pull this setting. - var serviceCollection = new ServiceCollection() - .AddLogging(configure => - configure.AddSerilog(new LoggerConfiguration() - // log level will be dynamically be controlled by our log interceptor upon running - .MinimumLevel.ControlledBy(LogInterceptor.LogLevel) - // the log enricher will add a new property with the log file path from the settings - // that we can use to set the path dynamically - .Enrich.With() - // serilog.sinks.map will defer the configuration of the sink to be ondemand - // allowing us to look at the properties set by the enricher to set the path appropriately - .WriteTo.Map(LoggingEnricher.LogFilePathPropertyName, - (logFilePath, wt) => wt.File($"{logFilePath}"), 1) - .CreateLogger() - ) - ); - - var registrar = new TypeRegistrar(serviceCollection); - var app = new CommandApp(registrar); - - app.Configure(config => - { - config.SetInterceptor(new LogInterceptor()); // add the interceptor + config.SetInterceptor(new LogInterceptor()); // add the interceptor config.AddCommand("hello"); - }); + }); - return app.Run(args); - } + return app.Run(args); } -} \ No newline at end of file +} diff --git a/examples/Console/Borders/Program.cs b/examples/Console/Borders/Program.cs index b9612f2..7d2f3c8 100644 --- a/examples/Console/Borders/Program.cs +++ b/examples/Console/Borders/Program.cs @@ -1,32 +1,32 @@ using Spectre.Console.Rendering; -namespace Spectre.Console.Examples -{ - public static class Program - { - public static void Main() - { - // Render panel borders - HorizontalRule("PANEL BORDERS"); - PanelBorders(); +namespace Spectre.Console.Examples; - // Render table borders - HorizontalRule("TABLE BORDERS"); - TableBorders(); +public static class Program +{ + public static void Main() + { + // Render panel borders + HorizontalRule("PANEL BORDERS"); + PanelBorders(); + + // Render table borders + HorizontalRule("TABLE BORDERS"); + TableBorders(); + } + + private static void PanelBorders() + { + static IRenderable CreatePanel(string name, BoxBorder border) + { + return new Panel($"This is a panel with\nthe [yellow]{name}[/] border.") + .Header($" [blue]{name}[/] ", Justify.Center) + .Border(border) + .BorderStyle(Style.Parse("grey")); } - private static void PanelBorders() + var items = new[] { - static IRenderable CreatePanel(string name, BoxBorder border) - { - return new Panel($"This is a panel with\nthe [yellow]{name}[/] border.") - .Header($" [blue]{name}[/] ", Justify.Center) - .Border(border) - .BorderStyle(Style.Parse("grey")); - } - - var items = new[] - { CreatePanel("Ascii", BoxBorder.Ascii), CreatePanel("Square", BoxBorder.Square), CreatePanel("Rounded", BoxBorder.Rounded), @@ -35,29 +35,29 @@ namespace Spectre.Console.Examples CreatePanel("None", BoxBorder.None), }; - AnsiConsole.Write( - new Padder( - new Columns(items).PadRight(2), - new Padding(2,0,0,0))); + AnsiConsole.Write( + new Padder( + new Columns(items).PadRight(2), + new Padding(2, 0, 0, 0))); + } + + private static void TableBorders() + { + static IRenderable CreateTable(string name, TableBorder border) + { + var table = new Table().Border(border); + table.AddColumn("[yellow]Header 1[/]", c => c.Footer("[grey]Footer 1[/]")); + table.AddColumn("[yellow]Header 2[/]", col => col.Footer("[grey]Footer 2[/]").RightAligned()); + table.AddRow("Cell", "Cell"); + table.AddRow("Cell", "Cell"); + + return new Panel(table) + .Header($" [blue]{name}[/] ", Justify.Center) + .NoBorder(); } - private static void TableBorders() + var items = new[] { - static IRenderable CreateTable(string name, TableBorder border) - { - var table = new Table().Border(border); - table.AddColumn("[yellow]Header 1[/]", c => c.Footer("[grey]Footer 1[/]")); - table.AddColumn("[yellow]Header 2[/]", col => col.Footer("[grey]Footer 2[/]").RightAligned()); - table.AddRow("Cell", "Cell"); - table.AddRow("Cell", "Cell"); - - return new Panel(table) - .Header($" [blue]{name}[/] ", Justify.Center) - .NoBorder(); - } - - var items = new[] - { CreateTable("Ascii", TableBorder.Ascii), CreateTable("Ascii2", TableBorder.Ascii2), CreateTable("AsciiDoubleHead", TableBorder.AsciiDoubleHead), @@ -77,14 +77,13 @@ namespace Spectre.Console.Examples CreateTable("Markdown", TableBorder.Markdown), }; - AnsiConsole.Write(new Columns(items).Collapse()); - } + AnsiConsole.Write(new Columns(items).Collapse()); + } - private static void HorizontalRule(string title) - { - AnsiConsole.WriteLine(); - AnsiConsole.Write(new Rule($"[white bold]{title}[/]").RuleStyle("grey").LeftAligned()); - AnsiConsole.WriteLine(); - } + private static void HorizontalRule(string title) + { + AnsiConsole.WriteLine(); + AnsiConsole.Write(new Rule($"[white bold]{title}[/]").RuleStyle("grey").LeftAligned()); + AnsiConsole.WriteLine(); } } diff --git a/examples/Console/Calendars/Program.cs b/examples/Console/Calendars/Program.cs index b4a6be3..063467d 100644 --- a/examples/Console/Calendars/Program.cs +++ b/examples/Console/Calendars/Program.cs @@ -1,17 +1,16 @@ -namespace Spectre.Console.Examples +namespace Spectre.Console.Examples; + +public static class Program { - public static class Program + public static void Main(string[] args) { - public static void Main(string[] args) - { - AnsiConsole.WriteLine(); - AnsiConsole.Write(new Calendar(2020, 10) - .RoundedBorder() - .HighlightStyle(Style.Parse("red")) - .HeaderStyle(Style.Parse("yellow")) - .AddCalendarEvent("An event", 2020, 9, 22) - .AddCalendarEvent("Another event", 2020, 10, 2) - .AddCalendarEvent("A third event", 2020, 10, 13)); - } + AnsiConsole.WriteLine(); + AnsiConsole.Write(new Calendar(2020, 10) + .RoundedBorder() + .HighlightStyle(Style.Parse("red")) + .HeaderStyle(Style.Parse("yellow")) + .AddCalendarEvent("An event", 2020, 9, 22) + .AddCalendarEvent("Another event", 2020, 10, 2) + .AddCalendarEvent("A third event", 2020, 10, 13)); } } diff --git a/examples/Console/Canvas/Mandelbrot.cs b/examples/Console/Canvas/Mandelbrot.cs index 005b2d1..c3d18d9 100644 --- a/examples/Console/Canvas/Mandelbrot.cs +++ b/examples/Console/Canvas/Mandelbrot.cs @@ -5,82 +5,81 @@ Licensed under GNU Free Documentation License 1.2 using System; -namespace Spectre.Console.Examples +namespace Spectre.Console.Examples; + +public static class Mandelbrot { - public static class Mandelbrot + private const double MaxValueExtent = 2.0; + + private struct ComplexNumber { - private const double MaxValueExtent = 2.0; + public double Real { get; } + public double Imaginary { get; } - private struct ComplexNumber + public ComplexNumber(double real, double imaginary) { - public double Real { get; } - public double Imaginary { get; } - - public ComplexNumber(double real, double imaginary) - { - Real = real; - Imaginary = imaginary; - } - - public static ComplexNumber operator +(ComplexNumber x, ComplexNumber y) - { - return new ComplexNumber(x.Real + y.Real, x.Imaginary + y.Imaginary); - } - - public static ComplexNumber operator *(ComplexNumber x, ComplexNumber y) - { - return new ComplexNumber(x.Real * y.Real - x.Imaginary * y.Imaginary, - x.Real * y.Imaginary + x.Imaginary * y.Real); - } - - public double Abs() - { - return Real * Real + Imaginary * Imaginary; - } + Real = real; + Imaginary = imaginary; } - public static Canvas Generate(int width, int height) + public static ComplexNumber operator +(ComplexNumber x, ComplexNumber y) { - var canvas = new Canvas(width, height); - - var scale = 2 * MaxValueExtent / Math.Min(canvas.Width, canvas.Height); - for (var i = 0; i < canvas.Height; i++) - { - var y = (canvas.Height / 2 - i) * scale; - for (var j = 0; j < canvas.Width; j++) - { - var x = (j - canvas.Width / 2) * scale; - var value = Calculate(new ComplexNumber(x, y)); - canvas.SetPixel(j, i, GetColor(value)); - } - } - - return canvas; + return new ComplexNumber(x.Real + y.Real, x.Imaginary + y.Imaginary); } - private static double Calculate(ComplexNumber c) + public static ComplexNumber operator *(ComplexNumber x, ComplexNumber y) { - const int MaxIterations = 1000; - const double MaxNorm = MaxValueExtent * MaxValueExtent; - - var iteration = 0; - var z = new ComplexNumber(); - do - { - z = z * z + c; - iteration++; - } while (z.Abs() < MaxNorm && iteration < MaxIterations); - - return iteration < MaxIterations - ? (double)iteration / MaxIterations - : 0; + return new ComplexNumber(x.Real * y.Real - x.Imaginary * y.Imaginary, + x.Real * y.Imaginary + x.Imaginary * y.Real); } - private static Color GetColor(double value) + public double Abs() { - const double MaxColor = 256; - const double ContrastValue = 0.2; - return new Color(0, 0, (byte)(MaxColor * Math.Pow(value, ContrastValue))); + return Real * Real + Imaginary * Imaginary; } } + + public static Canvas Generate(int width, int height) + { + var canvas = new Canvas(width, height); + + var scale = 2 * MaxValueExtent / Math.Min(canvas.Width, canvas.Height); + for (var i = 0; i < canvas.Height; i++) + { + var y = (canvas.Height / 2 - i) * scale; + for (var j = 0; j < canvas.Width; j++) + { + var x = (j - canvas.Width / 2) * scale; + var value = Calculate(new ComplexNumber(x, y)); + canvas.SetPixel(j, i, GetColor(value)); + } + } + + return canvas; + } + + private static double Calculate(ComplexNumber c) + { + const int MaxIterations = 1000; + const double MaxNorm = MaxValueExtent * MaxValueExtent; + + var iteration = 0; + var z = new ComplexNumber(); + do + { + z = z * z + c; + iteration++; + } while (z.Abs() < MaxNorm && iteration < MaxIterations); + + return iteration < MaxIterations + ? (double)iteration / MaxIterations + : 0; + } + + private static Color GetColor(double value) + { + const double MaxColor = 256; + const double ContrastValue = 0.2; + return new Color(0, 0, (byte)(MaxColor * Math.Pow(value, ContrastValue))); + } } diff --git a/examples/Console/Canvas/Program.cs b/examples/Console/Canvas/Program.cs index b7fad39..4014e2c 100644 --- a/examples/Console/Canvas/Program.cs +++ b/examples/Console/Canvas/Program.cs @@ -3,45 +3,44 @@ using System.Reflection; using SixLabors.ImageSharp.Processing; using Spectre.Console.Rendering; -namespace Spectre.Console.Examples +namespace Spectre.Console.Examples; + +public static class Program { - public static class Program + public static void Main() { - public static void Main() + // Draw a mandelbrot set using a Canvas + var mandelbrot = Mandelbrot.Generate(32, 32); + Render(mandelbrot, "Mandelbrot"); + + // Draw an image using CanvasImage powered by ImageSharp. + // This requires the "Spectre.Console.ImageSharp" NuGet package. + var image = new CanvasImage("cake.png"); + image.BilinearResampler(); + image.MaxWidth(16); + Render(image, "Image from file (16 wide)"); + + // Draw image again, but without render width + image.NoMaxWidth(); + image.Mutate(ctx => ctx.Grayscale().Rotate(-45).EntropyCrop()); + Render(image, "Image from file (fit, greyscale, rotated)"); + + // Draw image again, but load from embedded resource rather than file + using (var fileStream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Canvas.cake.png")) { - // Draw a mandelbrot set using a Canvas - var mandelbrot = Mandelbrot.Generate(32, 32); - Render(mandelbrot, "Mandelbrot"); - - // Draw an image using CanvasImage powered by ImageSharp. - // This requires the "Spectre.Console.ImageSharp" NuGet package. - var image = new CanvasImage("cake.png"); - image.BilinearResampler(); - image.MaxWidth(16); - Render(image, "Image from file (16 wide)"); - - // Draw image again, but without render width - image.NoMaxWidth(); - image.Mutate(ctx => ctx.Grayscale().Rotate(-45).EntropyCrop()); - Render(image, "Image from file (fit, greyscale, rotated)"); - - // Draw image again, but load from embedded resource rather than file - using (var fileStream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Canvas.cake.png")) - { - Debug.Assert(fileStream != null); - var embeddedImage = new CanvasImage(fileStream); - embeddedImage.BilinearResampler(); - embeddedImage.MaxWidth(16); - Render(embeddedImage, "Image from embedded resource (16 wide)"); - } - } - - private static void Render(IRenderable canvas, string title) - { - AnsiConsole.WriteLine(); - AnsiConsole.Write(new Rule($"[yellow]{title}[/]").LeftAligned().RuleStyle("grey")); - AnsiConsole.WriteLine(); - AnsiConsole.Write(canvas); + Debug.Assert(fileStream != null); + var embeddedImage = new CanvasImage(fileStream); + embeddedImage.BilinearResampler(); + embeddedImage.MaxWidth(16); + Render(embeddedImage, "Image from embedded resource (16 wide)"); } } + + private static void Render(IRenderable canvas, string title) + { + AnsiConsole.WriteLine(); + AnsiConsole.Write(new Rule($"[yellow]{title}[/]").LeftAligned().RuleStyle("grey")); + AnsiConsole.WriteLine(); + AnsiConsole.Write(canvas); + } } diff --git a/examples/Console/Charts/Program.cs b/examples/Console/Charts/Program.cs index c80a750..cd25bdf 100644 --- a/examples/Console/Charts/Program.cs +++ b/examples/Console/Charts/Program.cs @@ -1,41 +1,40 @@ using Spectre.Console.Rendering; -namespace Spectre.Console.Examples +namespace Spectre.Console.Examples; + +public static class Program { - public static class Program + public static void Main() { - public static void Main() - { - // Render a bar chart - AnsiConsole.WriteLine(); - Render("Fruits per month", new BarChart() - .Width(60) - .Label("[green bold underline]Number of fruits[/]") - .CenterLabel() - .AddItem("Apple", 12, Color.Yellow) - .AddItem("Orange", 54, Color.Green) - .AddItem("Banana", 33, Color.Red)); + // Render a bar chart + AnsiConsole.WriteLine(); + Render("Fruits per month", new BarChart() + .Width(60) + .Label("[green bold underline]Number of fruits[/]") + .CenterLabel() + .AddItem("Apple", 12, Color.Yellow) + .AddItem("Orange", 54, Color.Green) + .AddItem("Banana", 33, Color.Red)); - // Render a breakdown chart - AnsiConsole.WriteLine(); - Render("Languages used", new BreakdownChart() - .FullSize() - .Width(60) - .ShowPercentage() - .AddItem("SCSS", 37, Color.Red) - .AddItem("HTML", 28.3, Color.Blue) - .AddItem("C#", 22.6, Color.Green) - .AddItem("JavaScript", 6, Color.Yellow) - .AddItem("Ruby", 6, Color.LightGreen) - .AddItem("Shell", 0.1, Color.Aqua)); - } + // Render a breakdown chart + AnsiConsole.WriteLine(); + Render("Languages used", new BreakdownChart() + .FullSize() + .Width(60) + .ShowPercentage() + .AddItem("SCSS", 37, Color.Red) + .AddItem("HTML", 28.3, Color.Blue) + .AddItem("C#", 22.6, Color.Green) + .AddItem("JavaScript", 6, Color.Yellow) + .AddItem("Ruby", 6, Color.LightGreen) + .AddItem("Shell", 0.1, Color.Aqua)); + } - private static void Render(string title, IRenderable chart) - { - AnsiConsole.Write( - new Panel(chart) - .Padding(1, 1) - .Header(title)); - } + private static void Render(string title, IRenderable chart) + { + AnsiConsole.Write( + new Panel(chart) + .Padding(1, 1) + .Header(title)); } } diff --git a/examples/Console/Colors/Program.cs b/examples/Console/Colors/Program.cs index 5ac6737..20e5735 100644 --- a/examples/Console/Colors/Program.cs +++ b/examples/Console/Colors/Program.cs @@ -1,103 +1,102 @@ -namespace Spectre.Console.Examples +namespace Spectre.Console.Examples; + +public static class Program { - public static class Program + public static void Main() { - public static void Main() + ///////////////////////////////////////////////////////////////// + // No colors + ///////////////////////////////////////////////////////////////// + if (AnsiConsole.Profile.Capabilities.ColorSystem == ColorSystem.NoColors) { - ///////////////////////////////////////////////////////////////// - // No colors - ///////////////////////////////////////////////////////////////// - if (AnsiConsole.Profile.Capabilities.ColorSystem == ColorSystem.NoColors) - { - AnsiConsole.WriteLine("No colors are supported."); - return; - } + AnsiConsole.WriteLine("No colors are supported."); + return; + } - ///////////////////////////////////////////////////////////////// - // 3-BIT - ///////////////////////////////////////////////////////////////// - if (AnsiConsole.Profile.Supports(ColorSystem.Legacy)) + ///////////////////////////////////////////////////////////////// + // 3-BIT + ///////////////////////////////////////////////////////////////// + if (AnsiConsole.Profile.Supports(ColorSystem.Legacy)) + { + AnsiConsole.ResetColors(); + AnsiConsole.WriteLine(); + AnsiConsole.Write(new Rule("[yellow bold underline]3-bit Colors[/]").RuleStyle("grey").LeftAligned()); + AnsiConsole.WriteLine(); + + for (var i = 0; i < 8; i++) { + AnsiConsole.Background = Color.FromInt32(i); + AnsiConsole.Foreground = AnsiConsole.Background.GetInvertedColor(); + AnsiConsole.Write(string.Format(" {0,-9}", AnsiConsole.Background.ToString())); AnsiConsole.ResetColors(); - AnsiConsole.WriteLine(); - AnsiConsole.Write(new Rule("[yellow bold underline]3-bit Colors[/]").RuleStyle("grey").LeftAligned()); - AnsiConsole.WriteLine(); - - for (var i = 0; i < 8; i++) + if ((i + 1) % 8 == 0) { - AnsiConsole.Background = Color.FromInt32(i); + AnsiConsole.WriteLine(); + } + } + } + + ///////////////////////////////////////////////////////////////// + // 4-BIT + ///////////////////////////////////////////////////////////////// + if (AnsiConsole.Profile.Supports(ColorSystem.Standard)) + { + AnsiConsole.ResetColors(); + AnsiConsole.WriteLine(); + AnsiConsole.Write(new Rule("[yellow bold underline]4-bit Colors[/]").RuleStyle("grey").LeftAligned()); + AnsiConsole.WriteLine(); + + for (var i = 0; i < 16; i++) + { + AnsiConsole.Background = Color.FromInt32(i); + AnsiConsole.Foreground = AnsiConsole.Background.GetInvertedColor(); + AnsiConsole.Write(string.Format(" {0,-9}", AnsiConsole.Background.ToString())); + AnsiConsole.ResetColors(); + if ((i + 1) % 8 == 0) + { + AnsiConsole.WriteLine(); + } + } + } + + ///////////////////////////////////////////////////////////////// + // 8-BIT + ///////////////////////////////////////////////////////////////// + if (AnsiConsole.Profile.Supports(ColorSystem.EightBit)) + { + AnsiConsole.ResetColors(); + AnsiConsole.WriteLine(); + AnsiConsole.Write(new Rule("[yellow bold underline]8-bit Colors[/]").RuleStyle("grey").LeftAligned()); + AnsiConsole.WriteLine(); + + for (var i = 0; i < 16; i++) + { + for (var j = 0; j < 16; j++) + { + var number = i * 16 + j; + AnsiConsole.Background = Color.FromInt32(number); AnsiConsole.Foreground = AnsiConsole.Background.GetInvertedColor(); - AnsiConsole.Write(string.Format(" {0,-9}", AnsiConsole.Background.ToString())); + AnsiConsole.Write(string.Format(" {0,-4}", number)); AnsiConsole.ResetColors(); - if ((i + 1) % 8 == 0) + if ((number + 1) % 16 == 0) { AnsiConsole.WriteLine(); } } } + } - ///////////////////////////////////////////////////////////////// - // 4-BIT - ///////////////////////////////////////////////////////////////// - if (AnsiConsole.Profile.Supports(ColorSystem.Standard)) - { - AnsiConsole.ResetColors(); - AnsiConsole.WriteLine(); - AnsiConsole.Write(new Rule("[yellow bold underline]4-bit Colors[/]").RuleStyle("grey").LeftAligned()); - AnsiConsole.WriteLine(); + ///////////////////////////////////////////////////////////////// + // 24-BIT + ///////////////////////////////////////////////////////////////// + if (AnsiConsole.Profile.Supports(ColorSystem.TrueColor)) + { + AnsiConsole.ResetColors(); + AnsiConsole.WriteLine(); + AnsiConsole.Write(new Rule("[yellow bold underline]24-bit Colors[/]").RuleStyle("grey").LeftAligned()); + AnsiConsole.WriteLine(); - for (var i = 0; i < 16; i++) - { - AnsiConsole.Background = Color.FromInt32(i); - AnsiConsole.Foreground = AnsiConsole.Background.GetInvertedColor(); - AnsiConsole.Write(string.Format(" {0,-9}", AnsiConsole.Background.ToString())); - AnsiConsole.ResetColors(); - if ((i + 1) % 8 == 0) - { - AnsiConsole.WriteLine(); - } - } - } - - ///////////////////////////////////////////////////////////////// - // 8-BIT - ///////////////////////////////////////////////////////////////// - if (AnsiConsole.Profile.Supports(ColorSystem.EightBit)) - { - AnsiConsole.ResetColors(); - AnsiConsole.WriteLine(); - AnsiConsole.Write(new Rule("[yellow bold underline]8-bit Colors[/]").RuleStyle("grey").LeftAligned()); - AnsiConsole.WriteLine(); - - for (var i = 0; i < 16; i++) - { - for (var j = 0; j < 16; j++) - { - var number = i * 16 + j; - AnsiConsole.Background = Color.FromInt32(number); - AnsiConsole.Foreground = AnsiConsole.Background.GetInvertedColor(); - AnsiConsole.Write(string.Format(" {0,-4}", number)); - AnsiConsole.ResetColors(); - if ((number + 1) % 16 == 0) - { - AnsiConsole.WriteLine(); - } - } - } - } - - ///////////////////////////////////////////////////////////////// - // 24-BIT - ///////////////////////////////////////////////////////////////// - if (AnsiConsole.Profile.Supports(ColorSystem.TrueColor)) - { - AnsiConsole.ResetColors(); - AnsiConsole.WriteLine(); - AnsiConsole.Write(new Rule("[yellow bold underline]24-bit Colors[/]").RuleStyle("grey").LeftAligned()); - AnsiConsole.WriteLine(); - - AnsiConsole.Write(new ColorBox(width: 80, height: 15)); - } + AnsiConsole.Write(new ColorBox(width: 80, height: 15)); } } } diff --git a/examples/Console/Columns/Program.cs b/examples/Console/Columns/Program.cs index 83caa8a..9c94158 100644 --- a/examples/Console/Columns/Program.cs +++ b/examples/Console/Columns/Program.cs @@ -1,30 +1,29 @@ using System.Collections.Generic; -namespace Spectre.Console.Examples +namespace Spectre.Console.Examples; + +public static class Program { - public static class Program + public static void Main() { - public static void Main() + var cards = new List(); + foreach (var user in User.LoadUsers()) { - var cards = new List(); - foreach(var user in User.LoadUsers()) - { - cards.Add( - new Panel(GetCardContent(user)) - .Header($"{user.Country}") - .RoundedBorder().Expand()); - } - - // Render all cards in columns - AnsiConsole.Write(new Columns(cards)); + cards.Add( + new Panel(GetCardContent(user)) + .Header($"{user.Country}") + .RoundedBorder().Expand()); } - private static string GetCardContent(User user) - { - var name = $"{user.FirstName} {user.LastName}"; - var city = $"{user.City}"; + // Render all cards in columns + AnsiConsole.Write(new Columns(cards)); + } - return $"[b]{name}[/]\n[yellow]{city}[/]"; - } + private static string GetCardContent(User user) + { + var name = $"{user.FirstName} {user.LastName}"; + var city = $"{user.City}"; + + return $"[b]{name}[/]\n[yellow]{city}[/]"; } } diff --git a/examples/Console/Columns/User.cs b/examples/Console/Columns/User.cs index 88e5fc7..0c6a95a 100644 --- a/examples/Console/Columns/User.cs +++ b/examples/Console/Columns/User.cs @@ -1,17 +1,17 @@ using System.Collections.Generic; -namespace Spectre.Console.Examples -{ - public sealed class User - { - public string FirstName { get; set; } - public string LastName { get; set; } - public string City { get; set; } - public string Country { get; set; } +namespace Spectre.Console.Examples; - public static List LoadUsers() - { - return new List +public sealed class User +{ + public string FirstName { get; set; } + public string LastName { get; set; } + public string City { get; set; } + public string Country { get; set; } + + public static List LoadUsers() + { + return new List { new User { @@ -84,6 +84,5 @@ namespace Spectre.Console.Examples Country = "Ireland", }, }; - } } } diff --git a/examples/Console/Cursor/Program.cs b/examples/Console/Cursor/Program.cs index 796b857..f8bbfcb 100644 --- a/examples/Console/Cursor/Program.cs +++ b/examples/Console/Cursor/Program.cs @@ -1,18 +1,17 @@ -namespace Spectre.Console.Examples +namespace Spectre.Console.Examples; + +public static class Program { - public static class Program + public static void Main(string[] args) { - public static void Main(string[] args) - { - AnsiConsole.Write("Hello"); + AnsiConsole.Write("Hello"); - // Move the cursor 3 cells to the right - AnsiConsole.Cursor.Move(CursorDirection.Right, 3); - AnsiConsole.Write("World"); + // Move the cursor 3 cells to the right + AnsiConsole.Cursor.Move(CursorDirection.Right, 3); + AnsiConsole.Write("World"); - // Move the cursor 5 cells to the left. - AnsiConsole.Cursor.Move(CursorDirection.Left, 5); - AnsiConsole.WriteLine("Universe"); - } + // Move the cursor 5 cells to the left. + AnsiConsole.Cursor.Move(CursorDirection.Left, 5); + AnsiConsole.WriteLine("Universe"); } } diff --git a/examples/Console/Emojis/Program.cs b/examples/Console/Emojis/Program.cs index 8946f02..5806bcb 100644 --- a/examples/Console/Emojis/Program.cs +++ b/examples/Console/Emojis/Program.cs @@ -1,22 +1,21 @@ -namespace Spectre.Console.Examples +namespace Spectre.Console.Examples; + +public static class Program { - public static class Program + public static void Main(string[] args) { - public static void Main(string[] args) - { - // Show a known emoji - RenderEmoji(); + // Show a known emoji + RenderEmoji(); - // Show a remapped emoji - Emoji.Remap("globe_showing_europe_africa", Emoji.Known.GrinningFaceWithSmilingEyes); - RenderEmoji(); - } + // Show a remapped emoji + Emoji.Remap("globe_showing_europe_africa", Emoji.Known.GrinningFaceWithSmilingEyes); + RenderEmoji(); + } - private static void RenderEmoji() - { - AnsiConsole.Write( - new Panel("[yellow]Hello :globe_showing_europe_africa:![/]") - .RoundedBorder()); - } + private static void RenderEmoji() + { + AnsiConsole.Write( + new Panel("[yellow]Hello :globe_showing_europe_africa:![/]") + .RoundedBorder()); } } diff --git a/examples/Console/Exceptions/Program.cs b/examples/Console/Exceptions/Program.cs index b05eafc..4fa2751 100644 --- a/examples/Console/Exceptions/Program.cs +++ b/examples/Console/Exceptions/Program.cs @@ -1,65 +1,64 @@ using System; using System.Security.Authentication; -namespace Spectre.Console.Examples +namespace Spectre.Console.Examples; + +public static class Program { - public static class Program + public static void Main(string[] args) { - public static void Main(string[] args) + try { - try - { - DoMagic(42, null); - } - catch (Exception ex) - { - AnsiConsole.WriteLine(); - AnsiConsole.Write(new Rule("Default").LeftAligned()); - AnsiConsole.WriteLine(); - AnsiConsole.WriteException(ex); + DoMagic(42, null); + } + catch (Exception ex) + { + AnsiConsole.WriteLine(); + AnsiConsole.Write(new Rule("Default").LeftAligned()); + AnsiConsole.WriteLine(); + AnsiConsole.WriteException(ex); - AnsiConsole.WriteLine(); - AnsiConsole.Write(new Rule("Compact").LeftAligned()); - AnsiConsole.WriteLine(); - AnsiConsole.WriteException(ex, ExceptionFormats.ShortenEverything | ExceptionFormats.ShowLinks); + AnsiConsole.WriteLine(); + AnsiConsole.Write(new Rule("Compact").LeftAligned()); + AnsiConsole.WriteLine(); + AnsiConsole.WriteException(ex, ExceptionFormats.ShortenEverything | ExceptionFormats.ShowLinks); - AnsiConsole.WriteLine(); - AnsiConsole.Write(new Rule("Compact + Custom colors").LeftAligned()); - AnsiConsole.WriteLine(); - AnsiConsole.WriteException(ex, new ExceptionSettings + AnsiConsole.WriteLine(); + AnsiConsole.Write(new Rule("Compact + Custom colors").LeftAligned()); + AnsiConsole.WriteLine(); + AnsiConsole.WriteException(ex, new ExceptionSettings + { + Format = ExceptionFormats.ShortenEverything | ExceptionFormats.ShowLinks, + Style = new ExceptionStyle { - Format = ExceptionFormats.ShortenEverything | ExceptionFormats.ShowLinks, - Style = new ExceptionStyle - { - Exception = new Style().Foreground(Color.Grey), - Message = new Style().Foreground(Color.White), - NonEmphasized = new Style().Foreground(Color.Cornsilk1), - Parenthesis = new Style().Foreground(Color.Cornsilk1), - Method = new Style().Foreground(Color.Red), - ParameterName = new Style().Foreground(Color.Cornsilk1), - ParameterType = new Style().Foreground(Color.Red), - Path = new Style().Foreground(Color.Red), - LineNumber = new Style().Foreground(Color.Cornsilk1), - } - }); - } - } - - private static void DoMagic(int foo, string[,] bar) - { - try - { - CheckCredentials(foo, bar); - } - catch(Exception ex) - { - throw new InvalidOperationException("Whaaat?", ex); - } - } - - private static void CheckCredentials(int qux, string[,] corgi) - { - throw new InvalidCredentialException("The credentials are invalid."); + Exception = new Style().Foreground(Color.Grey), + Message = new Style().Foreground(Color.White), + NonEmphasized = new Style().Foreground(Color.Cornsilk1), + Parenthesis = new Style().Foreground(Color.Cornsilk1), + Method = new Style().Foreground(Color.Red), + ParameterName = new Style().Foreground(Color.Cornsilk1), + ParameterType = new Style().Foreground(Color.Red), + Path = new Style().Foreground(Color.Red), + LineNumber = new Style().Foreground(Color.Cornsilk1), + } + }); } } + + private static void DoMagic(int foo, string[,] bar) + { + try + { + CheckCredentials(foo, bar); + } + catch (Exception ex) + { + throw new InvalidOperationException("Whaaat?", ex); + } + } + + private static void CheckCredentials(int qux, string[,] corgi) + { + throw new InvalidCredentialException("The credentials are invalid."); + } } diff --git a/examples/Console/Figlet/Program.cs b/examples/Console/Figlet/Program.cs index 1abc4e2..c4f493b 100644 --- a/examples/Console/Figlet/Program.cs +++ b/examples/Console/Figlet/Program.cs @@ -1,12 +1,11 @@ -namespace Spectre.Console.Examples +namespace Spectre.Console.Examples; + +public static class Program { - public static class Program + public static void Main(string[] args) { - public static void Main(string[] args) - { - AnsiConsole.Write(new FigletText("Left aligned").LeftAligned().Color(Color.Red)); - AnsiConsole.Write(new FigletText("Centered").Centered().Color(Color.Green)); - AnsiConsole.Write(new FigletText("Right aligned").RightAligned().Color(Color.Blue)); - } + AnsiConsole.Write(new FigletText("Left aligned").LeftAligned().Color(Color.Red)); + AnsiConsole.Write(new FigletText("Centered").Centered().Color(Color.Green)); + AnsiConsole.Write(new FigletText("Right aligned").RightAligned().Color(Color.Blue)); } } diff --git a/examples/Console/Grids/Program.cs b/examples/Console/Grids/Program.cs index 0f5c9f0..3060559 100644 --- a/examples/Console/Grids/Program.cs +++ b/examples/Console/Grids/Program.cs @@ -1,22 +1,21 @@ -namespace Spectre.Console.Examples +namespace Spectre.Console.Examples; + +public static class Program { - public static class Program + public static void Main() { - public static void Main() - { - AnsiConsole.WriteLine(); - AnsiConsole.MarkupLine("Usage: [grey]dotnet [blue]run[/] [[options]] [[[[--]] ...]]]][/]"); - AnsiConsole.WriteLine(); + AnsiConsole.WriteLine(); + AnsiConsole.MarkupLine("Usage: [grey]dotnet [blue]run[/] [[options]] [[[[--]] ...]]]][/]"); + AnsiConsole.WriteLine(); - var grid = new Grid(); - grid.AddColumn(new GridColumn().NoWrap()); - grid.AddColumn(new GridColumn().PadLeft(2)); - grid.AddRow("Options:"); - grid.AddRow(" [blue]-h[/], [blue]--help[/]", "Show command line help."); - grid.AddRow(" [blue]-c[/], [blue]--configuration[/] ", "The configuration to run for."); - grid.AddRow(" [blue]-v[/], [blue]--verbosity[/] ", "Set the [grey]MSBuild[/] verbosity level."); + var grid = new Grid(); + grid.AddColumn(new GridColumn().NoWrap()); + grid.AddColumn(new GridColumn().PadLeft(2)); + grid.AddRow("Options:"); + grid.AddRow(" [blue]-h[/], [blue]--help[/]", "Show command line help."); + grid.AddRow(" [blue]-c[/], [blue]--configuration[/] ", "The configuration to run for."); + grid.AddRow(" [blue]-v[/], [blue]--verbosity[/] ", "Set the [grey]MSBuild[/] verbosity level."); - AnsiConsole.Write(grid); - } + AnsiConsole.Write(grid); } } diff --git a/examples/Console/Info/Program.cs b/examples/Console/Info/Program.cs index 6e8a7ac..0b7a227 100644 --- a/examples/Console/Info/Program.cs +++ b/examples/Console/Info/Program.cs @@ -1,32 +1,31 @@ -namespace Spectre.Console.Examples +namespace Spectre.Console.Examples; + +public static class Program { - public static class Program + public static void Main() { - public static void Main() - { - var grid = new Grid() - .AddColumn(new GridColumn().NoWrap().PadRight(4)) - .AddColumn() - .AddRow("[b]Enrichers[/]", string.Join(", ", AnsiConsole.Profile.Enrichers)) - .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]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}"); + var grid = new Grid() + .AddColumn(new GridColumn().NoWrap().PadRight(4)) + .AddColumn() + .AddRow("[b]Enrichers[/]", string.Join(", ", AnsiConsole.Profile.Enrichers)) + .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]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}"); - AnsiConsole.Write( - new Panel(grid) - .Header("Information")); - } + AnsiConsole.Write( + new Panel(grid) + .Header("Information")); + } - private static string YesNo(bool value) - { - return value ? "Yes" : "No"; - } + private static string YesNo(bool value) + { + return value ? "Yes" : "No"; } } diff --git a/examples/Console/Links/Program.cs b/examples/Console/Links/Program.cs index 1977008..d13d0c2 100644 --- a/examples/Console/Links/Program.cs +++ b/examples/Console/Links/Program.cs @@ -1,19 +1,18 @@ -namespace Spectre.Console.Examples +namespace Spectre.Console.Examples; + +public static class Program { - public static class Program + public static void Main() { - public static void Main() + if (AnsiConsole.Profile.Capabilities.Links) { - if (AnsiConsole.Profile.Capabilities.Links) - { - AnsiConsole.MarkupLine("[link=https://patriksvensson.se]Click to visit my blog[/]!"); - } - else - { - AnsiConsole.MarkupLine("[red]It looks like your terminal doesn't support links[/]"); - AnsiConsole.WriteLine(); - AnsiConsole.MarkupLine("[yellow](╯°□°)╯[/]︵ [blue]┻━┻[/]"); - } + AnsiConsole.MarkupLine("[link=https://patriksvensson.se]Click to visit my blog[/]!"); + } + else + { + AnsiConsole.MarkupLine("[red]It looks like your terminal doesn't support links[/]"); + AnsiConsole.WriteLine(); + AnsiConsole.MarkupLine("[yellow](╯°□°)╯[/]︵ [blue]┻━┻[/]"); } } } diff --git a/examples/Console/Live/Program.cs b/examples/Console/Live/Program.cs index 18f0f5a..1ef424f 100644 --- a/examples/Console/Live/Program.cs +++ b/examples/Console/Live/Program.cs @@ -1,81 +1,80 @@ using System; using System.Threading; -namespace Spectre.Console.Examples -{ - public static class Program - { - public static void Main() - { - var table = new Table().Centered(); +namespace Spectre.Console.Examples; - // Animate - AnsiConsole.Live(table) - .AutoClear(false) - .Overflow(VerticalOverflow.Ellipsis) - .Cropping(VerticalOverflowCropping.Top) - .Start(ctx => +public static class Program +{ + public static void Main() + { + var table = new Table().Centered(); + + // Animate + AnsiConsole.Live(table) + .AutoClear(false) + .Overflow(VerticalOverflow.Ellipsis) + .Cropping(VerticalOverflowCropping.Top) + .Start(ctx => + { + void Update(int delay, Action action) { - void Update(int delay, Action action) - { - action(); - ctx.Refresh(); - Thread.Sleep(delay); - } + action(); + ctx.Refresh(); + Thread.Sleep(delay); + } // Columns Update(230, () => table.AddColumn("Release date")); - Update(230, () => table.AddColumn("Title")); - Update(230, () => table.AddColumn("Budget")); - Update(230, () => table.AddColumn("Opening Weekend")); - Update(230, () => table.AddColumn("Box office")); + Update(230, () => table.AddColumn("Title")); + Update(230, () => table.AddColumn("Budget")); + Update(230, () => table.AddColumn("Opening Weekend")); + Update(230, () => table.AddColumn("Box office")); // Rows Update(70, () => table.AddRow("May 25, 1977", "[yellow]Star Wars[/] [grey]Ep.[/] [u]IV[/]", "$11,000,000", "$1,554,475", "$775,398,007")); - Update(70, () => table.AddRow("May 21, 1980", "[yellow]Star Wars[/] [grey]Ep.[/] [u]V[/]", "$18,000,000", "$4,910,483", "$547,969,004")); - Update(70, () => table.AddRow("May 25, 1983", "[yellow]Star Wars[/] [grey]Ep.[/] [u]VI[/]", "$32,500,000", "$23,019,618", "$475,106,177")); - Update(70, () => table.AddRow("May 19, 1999", "[yellow]Star Wars[/] [grey]Ep.[/] [u]I[/]", "$115,000,000", "$64,810,870", "$1,027,044,677")); - Update(70, () => table.AddRow("May 16, 2002", "[yellow]Star Wars[/] [grey]Ep.[/] [u]II[/]", "$115,000,000", "$80,027,814", "$649,436,358")); - Update(70, () => table.AddRow("May 19, 2005", "[yellow]Star Wars[/] [grey]Ep.[/] [u]III[/]", "$113,000,000", "$108,435,841", "$850,035,635")); - Update(70, () => table.AddRow("Dec 18, 2015", "[yellow]Star Wars[/] [grey]Ep.[/] [u]VII[/]", "$245,000,000", "$247,966,675", "$2,068,223,624")); - Update(70, () => table.AddRow("Dec 15, 2017", "[yellow]Star Wars[/] [grey]Ep.[/] [u]VIII[/]", "$317,000,000", "$220,009,584", "$1,333,539,889")); - Update(70, () => table.AddRow("Dec 20, 2019", "[yellow]Star Wars[/] [grey]Ep.[/] [u]IX[/]", "$245,000,000", "$177,383,864", "$1,074,114,248")); + Update(70, () => table.AddRow("May 21, 1980", "[yellow]Star Wars[/] [grey]Ep.[/] [u]V[/]", "$18,000,000", "$4,910,483", "$547,969,004")); + Update(70, () => table.AddRow("May 25, 1983", "[yellow]Star Wars[/] [grey]Ep.[/] [u]VI[/]", "$32,500,000", "$23,019,618", "$475,106,177")); + Update(70, () => table.AddRow("May 19, 1999", "[yellow]Star Wars[/] [grey]Ep.[/] [u]I[/]", "$115,000,000", "$64,810,870", "$1,027,044,677")); + Update(70, () => table.AddRow("May 16, 2002", "[yellow]Star Wars[/] [grey]Ep.[/] [u]II[/]", "$115,000,000", "$80,027,814", "$649,436,358")); + Update(70, () => table.AddRow("May 19, 2005", "[yellow]Star Wars[/] [grey]Ep.[/] [u]III[/]", "$113,000,000", "$108,435,841", "$850,035,635")); + Update(70, () => table.AddRow("Dec 18, 2015", "[yellow]Star Wars[/] [grey]Ep.[/] [u]VII[/]", "$245,000,000", "$247,966,675", "$2,068,223,624")); + Update(70, () => table.AddRow("Dec 15, 2017", "[yellow]Star Wars[/] [grey]Ep.[/] [u]VIII[/]", "$317,000,000", "$220,009,584", "$1,333,539,889")); + Update(70, () => table.AddRow("Dec 20, 2019", "[yellow]Star Wars[/] [grey]Ep.[/] [u]IX[/]", "$245,000,000", "$177,383,864", "$1,074,114,248")); // Column footer Update(230, () => table.Columns[2].Footer("$1,633,000,000")); - Update(230, () => table.Columns[3].Footer("$928,119,224")); - Update(400, () => table.Columns[4].Footer("$10,318,030,576")); + Update(230, () => table.Columns[3].Footer("$928,119,224")); + Update(400, () => table.Columns[4].Footer("$10,318,030,576")); // Column alignment Update(230, () => table.Columns[2].RightAligned()); - Update(230, () => table.Columns[3].RightAligned()); - Update(400, () => table.Columns[4].RightAligned()); + Update(230, () => table.Columns[3].RightAligned()); + Update(400, () => table.Columns[4].RightAligned()); // Column titles Update(70, () => table.Columns[0].Header("[bold]Release date[/]")); - Update(70, () => table.Columns[1].Header("[bold]Title[/]")); - Update(70, () => table.Columns[2].Header("[red bold]Budget[/]")); - Update(70, () => table.Columns[3].Header("[green bold]Opening Weekend[/]")); - Update(400, () => table.Columns[4].Header("[blue bold]Box office[/]")); + Update(70, () => table.Columns[1].Header("[bold]Title[/]")); + Update(70, () => table.Columns[2].Header("[red bold]Budget[/]")); + Update(70, () => table.Columns[3].Header("[green bold]Opening Weekend[/]")); + Update(400, () => table.Columns[4].Header("[blue bold]Box office[/]")); // Footers Update(70, () => table.Columns[2].Footer("[red bold]$1,633,000,000[/]")); - Update(70, () => table.Columns[3].Footer("[green bold]$928,119,224[/]")); - Update(400, () => table.Columns[4].Footer("[blue bold]$10,318,030,576[/]")); + Update(70, () => table.Columns[3].Footer("[green bold]$928,119,224[/]")); + Update(400, () => table.Columns[4].Footer("[blue bold]$10,318,030,576[/]")); // Title Update(500, () => table.Title("Star Wars Movies")); - Update(400, () => table.Title("[[ [yellow]Star Wars Movies[/] ]]")); + Update(400, () => table.Title("[[ [yellow]Star Wars Movies[/] ]]")); // Borders Update(230, () => table.BorderColor(Color.Yellow)); - Update(230, () => table.MinimalBorder()); - Update(230, () => table.SimpleBorder()); - Update(230, () => table.SimpleHeavyBorder()); + Update(230, () => table.MinimalBorder()); + Update(230, () => table.SimpleBorder()); + Update(230, () => table.SimpleHeavyBorder()); // Caption Update(400, () => table.Caption("[[ [blue]THE END[/] ]]")); - }); - } + }); } } diff --git a/examples/Console/LiveTable/Program.cs b/examples/Console/LiveTable/Program.cs index 2d61aa2..fccbd28 100644 --- a/examples/Console/LiveTable/Program.cs +++ b/examples/Console/LiveTable/Program.cs @@ -2,15 +2,15 @@ using System; using System.Linq; using System.Threading.Tasks; -namespace Spectre.Console.Examples -{ - public static class Program - { - private const int NumberOfRows = 10; +namespace Spectre.Console.Examples; - private static readonly Random _random = new(); - private static readonly string[] _exchanges = new string[] - { +public static class Program +{ + private const int NumberOfRows = 10; + + private static readonly Random _random = new(); + private static readonly string[] _exchanges = new string[] + { "SGD", "SEK", "PLN", "MYR", "EUR", "USD", "AUD", "JPY", "CNH", @@ -18,69 +18,68 @@ namespace Spectre.Console.Examples "DKK", "GBP", "RUB", "NZD", "MXN", "IDR", "TWD", "THB", "VND", - }; + }; - public static async Task Main(string[] args) - { - var table = new Table().Expand().BorderColor(Color.Grey); - table.AddColumn("[yellow]Source currency[/]"); - table.AddColumn("[yellow]Destination currency[/]"); - table.AddColumn("[yellow]Exchange rate[/]"); + public static async Task Main(string[] args) + { + var table = new Table().Expand().BorderColor(Color.Grey); + table.AddColumn("[yellow]Source currency[/]"); + table.AddColumn("[yellow]Destination currency[/]"); + table.AddColumn("[yellow]Exchange rate[/]"); - AnsiConsole.MarkupLine("Press [yellow]CTRL+C[/] to exit"); + AnsiConsole.MarkupLine("Press [yellow]CTRL+C[/] to exit"); - await AnsiConsole.Live(table) - .AutoClear(false) - .Overflow(VerticalOverflow.Ellipsis) - .Cropping(VerticalOverflowCropping.Bottom) - .StartAsync(async ctx => - { + await AnsiConsole.Live(table) + .AutoClear(false) + .Overflow(VerticalOverflow.Ellipsis) + .Cropping(VerticalOverflowCropping.Bottom) + .StartAsync(async ctx => + { // Add some initial rows foreach (var _ in Enumerable.Range(0, NumberOfRows)) - { - AddExchangeRateRow(table); - } + { + AddExchangeRateRow(table); + } // Continously update the table while (true) - { + { // More rows than we want? if (table.Rows.Count > NumberOfRows) - { + { // Remove the first one table.Rows.RemoveAt(0); - } + } // Add a new row AddExchangeRateRow(table); // Refresh and wait for a while ctx.Refresh(); - await Task.Delay(400); - } - }); - } + await Task.Delay(400); + } + }); + } - private static void AddExchangeRateRow(Table table) + private static void AddExchangeRateRow(Table table) + { + var (source, destination, rate) = GetExchangeRate(); + table.AddRow( + source, destination, + _random.NextDouble() > 0.35D ? $"[green]{rate}[/]" : $"[red]{rate}[/]"); + } + + private static (string Source, string Destination, double Rate) GetExchangeRate() + { + var source = _exchanges[_random.Next(0, _exchanges.Length)]; + var dest = _exchanges[_random.Next(0, _exchanges.Length)]; + var rate = 200 / ((_random.NextDouble() * 320) + 1); + + while (source == dest) { - var (source, destination, rate) = GetExchangeRate(); - table.AddRow( - source, destination, - _random.NextDouble() > 0.35D ? $"[green]{rate}[/]" : $"[red]{rate}[/]"); + dest = _exchanges[_random.Next(0, _exchanges.Length)]; } - private static (string Source, string Destination, double Rate) GetExchangeRate() - { - var source = _exchanges[_random.Next(0, _exchanges.Length)]; - var dest = _exchanges[_random.Next(0, _exchanges.Length)]; - var rate = 200 / ((_random.NextDouble() * 320) + 1); - - while (source == dest) - { - dest = _exchanges[_random.Next(0, _exchanges.Length)]; - } - - return (source, dest, rate); - } + return (source, dest, rate); } } diff --git a/examples/Console/Minimal/Program.cs b/examples/Console/Minimal/Program.cs index 025d073..6de47a3 100644 --- a/examples/Console/Minimal/Program.cs +++ b/examples/Console/Minimal/Program.cs @@ -9,5 +9,4 @@ Write(new Table() .RoundedBorder() .AddColumns("[red]Greeting[/]", "[red]Subject[/]") .AddRow("[yellow]Hello[/]", "World") - .AddRow("[green]Oh hi[/]", "[blue u]Mark[/]")); - + .AddRow("[green]Oh hi[/]", "[blue u]Mark[/]")); \ No newline at end of file diff --git a/examples/Console/Panels/Program.cs b/examples/Console/Panels/Program.cs index fa4fd61..e81dcf1 100644 --- a/examples/Console/Panels/Program.cs +++ b/examples/Console/Panels/Program.cs @@ -1,40 +1,39 @@ -namespace Spectre.Console.Examples +namespace Spectre.Console.Examples; + +public static class Program { - public static class Program + public static void Main() { - public static void Main() - { - var content = new Markup( - "[underline]I[/] heard [underline on blue]you[/] like panels\n\n\n\n" + - "So I put a panel in a panel").Centered(); + var content = new Markup( + "[underline]I[/] heard [underline on blue]you[/] like panels\n\n\n\n" + + "So I put a panel in a panel").Centered(); - AnsiConsole.Write( - new Panel( - new Panel(content) - .Border(BoxBorder.Rounded))); + AnsiConsole.Write( + new Panel( + new Panel(content) + .Border(BoxBorder.Rounded))); - // Left adjusted panel with text - AnsiConsole.Write( - new Panel(new Text("Left adjusted\nLeft").LeftAligned()) - .Expand() - .SquareBorder() - .Header("[red]Left[/]")); + // Left adjusted panel with text + AnsiConsole.Write( + new Panel(new Text("Left adjusted\nLeft").LeftAligned()) + .Expand() + .SquareBorder() + .Header("[red]Left[/]")); - // Centered ASCII panel with text - AnsiConsole.Write( - new Panel(new Text("Centered\nCenter").Centered()) - .Expand() - .AsciiBorder() - .Header("[green]Center[/]") - .HeaderAlignment(Justify.Center)); + // Centered ASCII panel with text + AnsiConsole.Write( + new Panel(new Text("Centered\nCenter").Centered()) + .Expand() + .AsciiBorder() + .Header("[green]Center[/]") + .HeaderAlignment(Justify.Center)); - // Right adjusted, rounded panel with text - AnsiConsole.Write( - new Panel(new Text("Right adjusted\nRight").RightAligned()) - .Expand() - .RoundedBorder() - .Header("[blue]Right[/]") - .HeaderAlignment(Justify.Right)); - } + // Right adjusted, rounded panel with text + AnsiConsole.Write( + new Panel(new Text("Right adjusted\nRight").RightAligned()) + .Expand() + .RoundedBorder() + .Header("[blue]Right[/]") + .HeaderAlignment(Justify.Right)); } } diff --git a/examples/Console/Progress/DescriptionGenerator.cs b/examples/Console/Progress/DescriptionGenerator.cs index 3f4f0a2..c3444e1 100644 --- a/examples/Console/Progress/DescriptionGenerator.cs +++ b/examples/Console/Progress/DescriptionGenerator.cs @@ -1,45 +1,44 @@ using System; using System.Collections.Generic; -namespace Spectre.Console.Examples +namespace Spectre.Console.Examples; + +public static class DescriptionGenerator { - public static class DescriptionGenerator + private static readonly string[] _verbs = new[] { "Downloading", "Rerouting", "Retriculating", "Collapsing", "Folding", "Solving", "Colliding", "Measuring" }; + private static readonly string[] _nouns = new[] { "internet", "splines", "space", "capacitators", "quarks", "algorithms", "data structures", "spacetime" }; + + private static readonly Random _random; + private static readonly HashSet _used; + + static DescriptionGenerator() { - private static readonly string[] _verbs = new[] { "Downloading", "Rerouting", "Retriculating", "Collapsing", "Folding", "Solving", "Colliding", "Measuring" }; - private static readonly string[] _nouns = new[] { "internet", "splines", "space", "capacitators", "quarks", "algorithms", "data structures", "spacetime" }; + _random = new Random(DateTime.Now.Millisecond); + _used = new HashSet(); + } - private static readonly Random _random; - private static readonly HashSet _used; - - static DescriptionGenerator() + public static bool TryGenerate(out string name) + { + var iterations = 0; + while (iterations < 25) { - _random = new Random(DateTime.Now.Millisecond); - _used = new HashSet(); - } - - public static bool TryGenerate(out string name) - { - var iterations = 0; - while (iterations < 25) + name = Generate(); + if (!_used.Contains(name)) { - name = Generate(); - if (!_used.Contains(name)) - { - _used.Add(name); - return true; - } - - iterations++; + _used.Add(name); + return true; } - name = Generate(); - return false; + iterations++; } - public static string Generate() - { - return _verbs[_random.Next(0, _verbs.Length)] - + " " + _nouns[_random.Next(0, _nouns.Length)]; - } + name = Generate(); + return false; + } + + public static string Generate() + { + return _verbs[_random.Next(0, _verbs.Length)] + + " " + _nouns[_random.Next(0, _nouns.Length)]; } } diff --git a/examples/Console/Progress/Program.cs b/examples/Console/Progress/Program.cs index b30f96d..86113f4 100644 --- a/examples/Console/Progress/Program.cs +++ b/examples/Console/Progress/Program.cs @@ -2,88 +2,87 @@ using System; using System.Collections.Generic; using System.Threading; -namespace Spectre.Console.Examples -{ - public static class Program - { - public static void Main() - { - AnsiConsole.MarkupLine("[yellow]Initializing warp drive[/]..."); +namespace Spectre.Console.Examples; - // Show progress - AnsiConsole.Progress() - .AutoClear(false) - .Columns(new ProgressColumn[] - { +public static class Program +{ + public static void Main() + { + AnsiConsole.MarkupLine("[yellow]Initializing warp drive[/]..."); + + // Show progress + AnsiConsole.Progress() + .AutoClear(false) + .Columns(new ProgressColumn[] + { new TaskDescriptionColumn(), // Task description new ProgressBarColumn(), // Progress bar new PercentageColumn(), // Percentage new RemainingTimeColumn(), // Remaining time new SpinnerColumn(), // Spinner - }) - .Start(ctx => - { - var random = new Random(DateTime.Now.Millisecond); + }) + .Start(ctx => + { + var random = new Random(DateTime.Now.Millisecond); // Create some tasks var tasks = CreateTasks(ctx, random); - var warpTask = ctx.AddTask("Going to warp", autoStart: false).IsIndeterminate(); + var warpTask = ctx.AddTask("Going to warp", autoStart: false).IsIndeterminate(); // Wait for all tasks (except the indeterminate one) to complete while (!ctx.IsFinished) - { + { // Increment progress foreach (var (task, increment) in tasks) - { - task.Increment(random.NextDouble() * increment); - } + { + task.Increment(random.NextDouble() * increment); + } // Write some random things to the terminal if (random.NextDouble() < 0.1) - { - WriteLogMessage(); - } + { + WriteLogMessage(); + } // Simulate some delay Thread.Sleep(100); - } + } // Now start the "warp" task warpTask.StartTask(); - warpTask.IsIndeterminate(false); - while (!ctx.IsFinished) - { - warpTask.Increment(12 * random.NextDouble()); + warpTask.IsIndeterminate(false); + while (!ctx.IsFinished) + { + warpTask.Increment(12 * random.NextDouble()); // Simulate some delay Thread.Sleep(100); - } - }); - - // Done - AnsiConsole.MarkupLine("[green]Done![/]"); - } - - private static List<(ProgressTask Task, int Delay)> CreateTasks(ProgressContext progress, Random random) - { - var tasks = new List<(ProgressTask, int)>(); - while (tasks.Count < 5) - { - if (DescriptionGenerator.TryGenerate(out var name)) - { - tasks.Add((progress.AddTask(name), random.Next(2, 10))); } - } + }); - return tasks; - } + // Done + AnsiConsole.MarkupLine("[green]Done![/]"); + } - private static void WriteLogMessage() + private static List<(ProgressTask Task, int Delay)> CreateTasks(ProgressContext progress, Random random) + { + var tasks = new List<(ProgressTask, int)>(); + while (tasks.Count < 5) { - AnsiConsole.MarkupLine( - "[grey]LOG:[/] " + - DescriptionGenerator.Generate() + - "[grey]...[/]"); + if (DescriptionGenerator.TryGenerate(out var name)) + { + tasks.Add((progress.AddTask(name), random.Next(2, 10))); + } } + + return tasks; + } + + private static void WriteLogMessage() + { + AnsiConsole.MarkupLine( + "[grey]LOG:[/] " + + DescriptionGenerator.Generate() + + "[grey]...[/]"); } } diff --git a/examples/Console/Prompt/Program.cs b/examples/Console/Prompt/Program.cs index 0703998..23b7f90 100644 --- a/examples/Console/Prompt/Program.cs +++ b/examples/Console/Prompt/Program.cs @@ -142,4 +142,4 @@ namespace Spectre.Console.Examples .AllowEmpty()); } } -} +} \ No newline at end of file diff --git a/examples/Console/Rules/Program.cs b/examples/Console/Rules/Program.cs index 6f20666..07f1bb2 100644 --- a/examples/Console/Rules/Program.cs +++ b/examples/Console/Rules/Program.cs @@ -1,41 +1,40 @@ -namespace Spectre.Console.Examples +namespace Spectre.Console.Examples; + +public static class Program { - public static class Program + public static void Main(string[] args) { - public static void Main(string[] args) - { - // No title - Render( - new Rule() - .RuleStyle(Style.Parse("yellow")) - .AsciiBorder() - .LeftAligned()); + // No title + Render( + new Rule() + .RuleStyle(Style.Parse("yellow")) + .AsciiBorder() + .LeftAligned()); - // Left aligned title - Render( - new Rule("[blue]Left aligned[/]") - .RuleStyle(Style.Parse("red")) - .DoubleBorder() - .LeftAligned()); + // Left aligned title + Render( + new Rule("[blue]Left aligned[/]") + .RuleStyle(Style.Parse("red")) + .DoubleBorder() + .LeftAligned()); - // Centered title - Render( - new Rule("[green]Centered[/]") - .RuleStyle(Style.Parse("green")) - .HeavyBorder() - .Centered()); + // Centered title + Render( + new Rule("[green]Centered[/]") + .RuleStyle(Style.Parse("green")) + .HeavyBorder() + .Centered()); - // Right aligned title - Render( - new Rule("[red]Right aligned[/]") - .RuleStyle(Style.Parse("blue")) - .RightAligned()); - } + // Right aligned title + Render( + new Rule("[red]Right aligned[/]") + .RuleStyle(Style.Parse("blue")) + .RightAligned()); + } - private static void Render(Rule rule) - { - AnsiConsole.Write(rule); - AnsiConsole.WriteLine(); - } + private static void Render(Rule rule) + { + AnsiConsole.Write(rule); + AnsiConsole.WriteLine(); } } diff --git a/examples/Console/Showcase/ExceptionGenerator.cs b/examples/Console/Showcase/ExceptionGenerator.cs index 1f9355e..8595485 100644 --- a/examples/Console/Showcase/ExceptionGenerator.cs +++ b/examples/Console/Showcase/ExceptionGenerator.cs @@ -1,30 +1,29 @@ using System; -namespace Spectre.Console.Examples +namespace Spectre.Console.Examples; + +public static class ExceptionGenerator { - public static class ExceptionGenerator + public static Exception GenerateException() { - public static Exception GenerateException() + try { - try - { - SomeOperation(); - throw new InvalidOperationException(); - } - catch (Exception ex) - { - return ex; - } + SomeOperation(); + throw new InvalidOperationException(); } - - private static void SomeOperation() + catch (Exception ex) { - SomeOperationGoingWrong(); - } - - private static void SomeOperationGoingWrong() - { - throw new InvalidOperationException("Something went very wrong!"); + return ex; } } + + private static void SomeOperation() + { + SomeOperationGoingWrong(); + } + + private static void SomeOperationGoingWrong() + { + throw new InvalidOperationException("Something went very wrong!"); + } } diff --git a/examples/Console/Showcase/Program.cs b/examples/Console/Showcase/Program.cs index e263f2f..e2c9713 100644 --- a/examples/Console/Showcase/Program.cs +++ b/examples/Console/Showcase/Program.cs @@ -1,153 +1,152 @@ using Spectre.Console.Rendering; -namespace Spectre.Console.Examples +namespace Spectre.Console.Examples; + +public static partial class Program { - public static partial class Program + public static void Main() { - public static void Main() - { - var table = new Table().HideHeaders().NoBorder(); - table.Title("[u][yellow]Spectre.Console[/] [b]Features[/][/]"); - table.AddColumn("Feature", c => c.NoWrap().RightAligned().Width(10).PadRight(3)); - table.AddColumn("Demonstration", c => c.PadRight(0)); - table.AddEmptyRow(); + var table = new Table().HideHeaders().NoBorder(); + table.Title("[u][yellow]Spectre.Console[/] [b]Features[/][/]"); + table.AddColumn("Feature", c => c.NoWrap().RightAligned().Width(10).PadRight(3)); + table.AddColumn("Demonstration", c => c.PadRight(0)); + table.AddEmptyRow(); - // Colors - table.AddRow( - new Markup("[red]Colors[/]"), - GetColorTable()); + // Colors + table.AddRow( + new Markup("[red]Colors[/]"), + GetColorTable()); - // Styles - table.AddEmptyRow(); - table.AddRow( - new Markup("[red]OS[/]"), - new Grid().Expand().AddColumns(3) - .AddRow( - "[bold green]Windows[/]", - "[bold blue]macOS[/]", - "[bold yellow]Linux[/]")); + // Styles + table.AddEmptyRow(); + table.AddRow( + new Markup("[red]OS[/]"), + new Grid().Expand().AddColumns(3) + .AddRow( + "[bold green]Windows[/]", + "[bold blue]macOS[/]", + "[bold yellow]Linux[/]")); - // Styles - table.AddEmptyRow(); - table.AddRow( - "[red]Styles[/]", - "All ansi styles: [bold]bold[/], [dim]dim[/], [italic]italic[/], [underline]underline[/], " - + "[strikethrough]strikethrough[/], [reverse]reverse[/], and even [blink]blink[/]."); + // Styles + table.AddEmptyRow(); + table.AddRow( + "[red]Styles[/]", + "All ansi styles: [bold]bold[/], [dim]dim[/], [italic]italic[/], [underline]underline[/], " + + "[strikethrough]strikethrough[/], [reverse]reverse[/], and even [blink]blink[/]."); - // Text - table.AddEmptyRow(); - table.AddRow( - new Markup("[red]Text[/]"), - new Markup("Word wrap text. Justify [green]left[/], [yellow]center[/] or [blue]right[/].")); + // Text + table.AddEmptyRow(); + table.AddRow( + new Markup("[red]Text[/]"), + new Markup("Word wrap text. Justify [green]left[/], [yellow]center[/] or [blue]right[/].")); - table.AddEmptyRow(); - table.AddRow( - Text.Empty, - GetTextGrid()); + table.AddEmptyRow(); + table.AddRow( + Text.Empty, + GetTextGrid()); - // Markup - table.AddEmptyRow(); - table.AddRow( - "[red]Markup[/]", - "[bold purple]Spectre.Console[/] supports a simple [i]bbcode[/] like " - + "[b]markup[/] for [yellow]color[/], [underline]style[/], and emoji! " - + ":thumbs_up: :red_apple: :ant: :bear: :baguette_bread: :bus:"); + // Markup + table.AddEmptyRow(); + table.AddRow( + "[red]Markup[/]", + "[bold purple]Spectre.Console[/] supports a simple [i]bbcode[/] like " + + "[b]markup[/] for [yellow]color[/], [underline]style[/], and emoji! " + + ":thumbs_up: :red_apple: :ant: :bear: :baguette_bread: :bus:"); - // Trees and tables - table.AddEmptyRow(); - table.AddRow( - new Markup("[red]Tables and Trees[/]"), - GetTreeTable()); + // Trees and tables + table.AddEmptyRow(); + table.AddRow( + new Markup("[red]Tables and Trees[/]"), + GetTreeTable()); - // Charts - table.AddRow( - new Markup("[red]Charts[/]"), - new Grid().Collapse().AddColumns(2).AddRow( - new Panel(GetBreakdownChart()).BorderColor(Color.Grey), - new Panel(GetBarChart()).BorderColor(Color.Grey))); + // Charts + table.AddRow( + new Markup("[red]Charts[/]"), + new Grid().Collapse().AddColumns(2).AddRow( + new Panel(GetBreakdownChart()).BorderColor(Color.Grey), + new Panel(GetBarChart()).BorderColor(Color.Grey))); - // Exceptions - table.AddEmptyRow(); - table.AddRow( - new Markup("[red]Exceptions[/]"), - ExceptionGenerator.GenerateException().GetRenderable()); + // Exceptions + table.AddEmptyRow(); + table.AddRow( + new Markup("[red]Exceptions[/]"), + ExceptionGenerator.GenerateException().GetRenderable()); - // Much more - table.AddEmptyRow(); - table.AddRow( - "[red]+ Much more![/]", - "Tables, Grids, Trees, Progress bars, Status, Bar charts, Calendars, Figlet, Images, Text prompts, " - + "List boxes, Separators, Pretty exceptions, Canvas, CLI parsing"); - table.AddEmptyRow(); + // Much more + table.AddEmptyRow(); + table.AddRow( + "[red]+ Much more![/]", + "Tables, Grids, Trees, Progress bars, Status, Bar charts, Calendars, Figlet, Images, Text prompts, " + + "List boxes, Separators, Pretty exceptions, Canvas, CLI parsing"); + table.AddEmptyRow(); - // Render the table - AnsiConsole.WriteLine(); - AnsiConsole.Write(table); - } + // Render the table + AnsiConsole.WriteLine(); + AnsiConsole.Write(table); + } - private static IRenderable GetColorTable() - { - var colorTable = new Table().Collapse().HideHeaders().NoBorder(); - colorTable.AddColumn("Desc", c => c.PadRight(3)).AddColumn("Colors", c => c.PadRight(0)); - colorTable.AddRow( - new Markup( - "✓ [bold grey]NO_COLOR support[/]\n" + - "✓ [bold green]3-bit color[/]\n" + - "✓ [bold blue]4-bit color[/]\n" + - "✓ [bold purple]8-bit color[/]\n" + - "✓ [bold yellow]Truecolor (16.7 million)[/]\n" + - "✓ [bold aqua]Automatic color conversion[/]"), - new ColorBox(height: 6)); + private static IRenderable GetColorTable() + { + var colorTable = new Table().Collapse().HideHeaders().NoBorder(); + colorTable.AddColumn("Desc", c => c.PadRight(3)).AddColumn("Colors", c => c.PadRight(0)); + colorTable.AddRow( + new Markup( + "✓ [bold grey]NO_COLOR support[/]\n" + + "✓ [bold green]3-bit color[/]\n" + + "✓ [bold blue]4-bit color[/]\n" + + "✓ [bold purple]8-bit color[/]\n" + + "✓ [bold yellow]Truecolor (16.7 million)[/]\n" + + "✓ [bold aqua]Automatic color conversion[/]"), + new ColorBox(height: 6)); - return colorTable; - } + return colorTable; + } - private static IRenderable GetTextGrid() - { - var loremTable = new Grid(); - var lorem = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque in metus sed sapien ultricies pretium a at justo. Maecenas luctus velit et auctor maximus."; - loremTable.AddColumn(new GridColumn().LeftAligned()); - loremTable.AddColumn(new GridColumn().Centered()); - loremTable.AddColumn(new GridColumn().RightAligned()); - loremTable.AddRow($"[green]{lorem}[/]", $"[yellow]{lorem}[/]", $"[blue]{lorem}[/]"); - return loremTable; - } + private static IRenderable GetTextGrid() + { + var loremTable = new Grid(); + var lorem = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque in metus sed sapien ultricies pretium a at justo. Maecenas luctus velit et auctor maximus."; + loremTable.AddColumn(new GridColumn().LeftAligned()); + loremTable.AddColumn(new GridColumn().Centered()); + loremTable.AddColumn(new GridColumn().RightAligned()); + loremTable.AddRow($"[green]{lorem}[/]", $"[yellow]{lorem}[/]", $"[blue]{lorem}[/]"); + return loremTable; + } - private static IRenderable GetTreeTable() - { - var tree = new Tree("📁 src"); - tree.AddNode("📁 foo").AddNode("📄 bar.cs"); - tree.AddNode("📁 baz").AddNode("📁 qux").AddNode("📄 corgi.txt"); - tree.AddNode("📄 waldo.xml"); + private static IRenderable GetTreeTable() + { + var tree = new Tree("📁 src"); + tree.AddNode("📁 foo").AddNode("📄 bar.cs"); + tree.AddNode("📁 baz").AddNode("📁 qux").AddNode("📄 corgi.txt"); + tree.AddNode("📄 waldo.xml"); - var table = new Table().SimpleBorder().BorderColor(Color.Grey); - table.AddColumn(new TableColumn("Overview")); - table.AddColumn(new TableColumn("").Footer("[grey]3 Files, 225 KiB[/]")); - table.AddRow(new Markup("[yellow]Files[/]"), tree); + var table = new Table().SimpleBorder().BorderColor(Color.Grey); + table.AddColumn(new TableColumn("Overview")); + table.AddColumn(new TableColumn("").Footer("[grey]3 Files, 225 KiB[/]")); + table.AddRow(new Markup("[yellow]Files[/]"), tree); - return new Table().RoundedBorder().Collapse().BorderColor(Color.Yellow) - .AddColumn("Foo").AddColumn("Bar") - .AddRow(new Text("Baz"), table) - .AddRow("Qux", "Corgi"); - } + return new Table().RoundedBorder().Collapse().BorderColor(Color.Yellow) + .AddColumn("Foo").AddColumn("Bar") + .AddRow(new Text("Baz"), table) + .AddRow("Qux", "Corgi"); + } - private static IRenderable GetBarChart() - { - return new BarChart() - .AddItem("Apple", 32, Color.Green) - .AddItem("Oranges", 13, Color.Orange1) - .AddItem("Bananas", 22, Color.Yellow); - } + private static IRenderable GetBarChart() + { + return new BarChart() + .AddItem("Apple", 32, Color.Green) + .AddItem("Oranges", 13, Color.Orange1) + .AddItem("Bananas", 22, Color.Yellow); + } - private static IRenderable GetBreakdownChart() - { - return new BreakdownChart() - .ShowPercentage() - .FullSize() - .AddItem("C#", 82, Color.Green) - .AddItem("PowerShell", 13, Color.Red) - .AddItem("Bash", 5, Color.Blue); - } + private static IRenderable GetBreakdownChart() + { + return new BreakdownChart() + .ShowPercentage() + .FullSize() + .AddItem("C#", 82, Color.Green) + .AddItem("PowerShell", 13, Color.Red) + .AddItem("Bash", 5, Color.Blue); } } diff --git a/examples/Console/Status/Program.cs b/examples/Console/Status/Program.cs index f0558ae..9ed3cfc 100644 --- a/examples/Console/Status/Program.cs +++ b/examples/Console/Status/Program.cs @@ -1,69 +1,68 @@ using System.Threading; -namespace Spectre.Console.Examples +namespace Spectre.Console.Examples; + +public static class Program { - public static class Program + public static void Main() { - public static void Main() - { - AnsiConsole.Status() - .AutoRefresh(true) - .Spinner(Spinner.Known.Default) - .Start("[yellow]Initializing warp drive[/]", ctx => - { + AnsiConsole.Status() + .AutoRefresh(true) + .Spinner(Spinner.Known.Default) + .Start("[yellow]Initializing warp drive[/]", ctx => + { // Initialize Thread.Sleep(3000); - WriteLogMessage("Starting gravimetric field displacement manifold"); - Thread.Sleep(1000); - WriteLogMessage("Warming up deuterium chamber"); - Thread.Sleep(2000); - WriteLogMessage("Generating antideuterium"); + WriteLogMessage("Starting gravimetric field displacement manifold"); + Thread.Sleep(1000); + WriteLogMessage("Warming up deuterium chamber"); + Thread.Sleep(2000); + WriteLogMessage("Generating antideuterium"); // Warp nacelles Thread.Sleep(3000); - ctx.Spinner(Spinner.Known.BouncingBar); - ctx.Status("[bold blue]Unfolding warp nacelles[/]"); - WriteLogMessage("Unfolding left warp nacelle"); - Thread.Sleep(2000); - WriteLogMessage("Left warp nacelle [green]online[/]"); - WriteLogMessage("Unfolding right warp nacelle"); - Thread.Sleep(1000); - WriteLogMessage("Right warp nacelle [green]online[/]"); + ctx.Spinner(Spinner.Known.BouncingBar); + ctx.Status("[bold blue]Unfolding warp nacelles[/]"); + WriteLogMessage("Unfolding left warp nacelle"); + Thread.Sleep(2000); + WriteLogMessage("Left warp nacelle [green]online[/]"); + WriteLogMessage("Unfolding right warp nacelle"); + Thread.Sleep(1000); + WriteLogMessage("Right warp nacelle [green]online[/]"); // Warp bubble Thread.Sleep(3000); - ctx.Spinner(Spinner.Known.Star2); - ctx.Status("[bold blue]Generating warp bubble[/]"); - Thread.Sleep(3000); - ctx.Spinner(Spinner.Known.Star); - ctx.Status("[bold blue]Stabilizing warp bubble[/]"); + ctx.Spinner(Spinner.Known.Star2); + ctx.Status("[bold blue]Generating warp bubble[/]"); + Thread.Sleep(3000); + ctx.Spinner(Spinner.Known.Star); + ctx.Status("[bold blue]Stabilizing warp bubble[/]"); // Safety ctx.Spinner(Spinner.Known.Monkey); - ctx.Status("[bold blue]Performing safety checks[/]"); - WriteLogMessage("Enabling interior dampening"); - Thread.Sleep(2000); - WriteLogMessage("Interior dampening [green]enabled[/]"); + ctx.Status("[bold blue]Performing safety checks[/]"); + WriteLogMessage("Enabling interior dampening"); + Thread.Sleep(2000); + WriteLogMessage("Interior dampening [green]enabled[/]"); // Warp! Thread.Sleep(3000); - ctx.Spinner(Spinner.Known.Moon); - WriteLogMessage("Preparing for warp"); - Thread.Sleep(1000); - for (var warp = 1; warp < 10; warp++) - { - ctx.Status($"[bold blue]Warp {warp}[/]"); - Thread.Sleep(500); - } - }); + ctx.Spinner(Spinner.Known.Moon); + WriteLogMessage("Preparing for warp"); + Thread.Sleep(1000); + for (var warp = 1; warp < 10; warp++) + { + ctx.Status($"[bold blue]Warp {warp}[/]"); + Thread.Sleep(500); + } + }); - // Done - AnsiConsole.MarkupLine("[bold green]Crusing at Warp 9.8[/]"); - } + // Done + AnsiConsole.MarkupLine("[bold green]Crusing at Warp 9.8[/]"); + } - private static void WriteLogMessage(string message) - { - AnsiConsole.MarkupLine($"[grey]LOG:[/] {message}[grey]...[/]"); - } + private static void WriteLogMessage(string message) + { + AnsiConsole.MarkupLine($"[grey]LOG:[/] {message}[grey]...[/]"); } } diff --git a/examples/Console/Tables/Program.cs b/examples/Console/Tables/Program.cs index 007b52d..096ef02 100644 --- a/examples/Console/Tables/Program.cs +++ b/examples/Console/Tables/Program.cs @@ -1,45 +1,44 @@ -namespace Spectre.Console.Examples +namespace Spectre.Console.Examples; + +public static class Program { - public static class Program + public static void Main() { - public static void Main() - { - AnsiConsole.Write(CreateTable()); - } + AnsiConsole.Write(CreateTable()); + } - private static Table CreateTable() - { - var simple = new Table() - .Border(TableBorder.Square) - .BorderColor(Color.Red) - .AddColumn(new TableColumn("[u]CDE[/]").Footer("EDC").Centered()) - .AddColumn(new TableColumn("[u]FED[/]").Footer("DEF")) - .AddColumn(new TableColumn("[u]IHG[/]").Footer("GHI")) - .AddRow("Hello", "[red]World![/]", "") - .AddRow("[blue]Bonjour[/]", "[white]le[/]", "[red]monde![/]") - .AddRow("[blue]Hej[/]", "[yellow]Världen![/]", ""); + private static Table CreateTable() + { + var simple = new Table() + .Border(TableBorder.Square) + .BorderColor(Color.Red) + .AddColumn(new TableColumn("[u]CDE[/]").Footer("EDC").Centered()) + .AddColumn(new TableColumn("[u]FED[/]").Footer("DEF")) + .AddColumn(new TableColumn("[u]IHG[/]").Footer("GHI")) + .AddRow("Hello", "[red]World![/]", "") + .AddRow("[blue]Bonjour[/]", "[white]le[/]", "[red]monde![/]") + .AddRow("[blue]Hej[/]", "[yellow]Världen![/]", ""); - var second = new Table() - .Border(TableBorder.Rounded) - .BorderColor(Color.Green) - .AddColumn(new TableColumn("[u]Foo[/]")) - .AddColumn(new TableColumn("[u]Bar[/]")) - .AddColumn(new TableColumn("[u]Baz[/]")) - .AddRow("Hello", "[red]World![/]", "") - .AddRow(simple, new Text("Whaaat"), new Text("Lolz")) - .AddRow("[blue]Hej[/]", "[yellow]Världen![/]", ""); + var second = new Table() + .Border(TableBorder.Rounded) + .BorderColor(Color.Green) + .AddColumn(new TableColumn("[u]Foo[/]")) + .AddColumn(new TableColumn("[u]Bar[/]")) + .AddColumn(new TableColumn("[u]Baz[/]")) + .AddRow("Hello", "[red]World![/]", "") + .AddRow(simple, new Text("Whaaat"), new Text("Lolz")) + .AddRow("[blue]Hej[/]", "[yellow]Världen![/]", ""); - return new Table() - .Centered() - .Border(TableBorder.DoubleEdge) - .Title("TABLE [yellow]TITLE[/]") - .Caption("TABLE [yellow]CAPTION[/]") - .AddColumn(new TableColumn(new Panel("[u]ABC[/]").BorderColor(Color.Red)).Footer("[u]FOOTER 1[/]")) - .AddColumn(new TableColumn(new Panel("[u]DEF[/]").BorderColor(Color.Green)).Footer("[u]FOOTER 2[/]")) - .AddColumn(new TableColumn(new Panel("[u]GHI[/]").BorderColor(Color.Blue)).Footer("[u]FOOTER 3[/]")) - .AddRow(new Text("Hello").Centered(), new Markup("[red]World![/]"), Text.Empty) - .AddRow(second, new Text("Whaaat"), new Text("Lol")) - .AddRow(new Markup("[blue]Hej[/]").Centered(), new Markup("[yellow]Världen![/]"), Text.Empty); - } + return new Table() + .Centered() + .Border(TableBorder.DoubleEdge) + .Title("TABLE [yellow]TITLE[/]") + .Caption("TABLE [yellow]CAPTION[/]") + .AddColumn(new TableColumn(new Panel("[u]ABC[/]").BorderColor(Color.Red)).Footer("[u]FOOTER 1[/]")) + .AddColumn(new TableColumn(new Panel("[u]DEF[/]").BorderColor(Color.Green)).Footer("[u]FOOTER 2[/]")) + .AddColumn(new TableColumn(new Panel("[u]GHI[/]").BorderColor(Color.Blue)).Footer("[u]FOOTER 3[/]")) + .AddRow(new Text("Hello").Centered(), new Markup("[red]World![/]"), Text.Empty) + .AddRow(second, new Text("Whaaat"), new Text("Lol")) + .AddRow(new Markup("[blue]Hej[/]").Centered(), new Markup("[yellow]Världen![/]"), Text.Empty); } } diff --git a/examples/Console/Trees/Program.cs b/examples/Console/Trees/Program.cs index 8a75651..6bdafa1 100644 --- a/examples/Console/Trees/Program.cs +++ b/examples/Console/Trees/Program.cs @@ -1,43 +1,42 @@ -namespace Spectre.Console.Examples +namespace Spectre.Console.Examples; + +public static class Program { - public static class Program + public static void Main() { - public static void Main() - { - AnsiConsole.WriteLine(); + AnsiConsole.WriteLine(); - // Render the tree - var tree = BuildTree(); - AnsiConsole.Write(tree); - } + // Render the tree + var tree = BuildTree(); + AnsiConsole.Write(tree); + } - private static Tree BuildTree() - { - // Create the tree - var tree = new Tree("Root") - .Style(Style.Parse("red")) - .Guide(TreeGuide.Line); + private static Tree BuildTree() + { + // Create the tree + var tree = new Tree("Root") + .Style(Style.Parse("red")) + .Guide(TreeGuide.Line); - // Add some nodes - var foo = tree.AddNode("[yellow]Foo[/]"); - var table = foo.AddNode(new Table() - .RoundedBorder() - .AddColumn("First") - .AddColumn("Second") - .AddRow("1", "2") - .AddRow("3", "4") - .AddRow("5", "6")); + // Add some nodes + var foo = tree.AddNode("[yellow]Foo[/]"); + var table = foo.AddNode(new Table() + .RoundedBorder() + .AddColumn("First") + .AddColumn("Second") + .AddRow("1", "2") + .AddRow("3", "4") + .AddRow("5", "6")); - table.AddNode("[blue]Baz[/]"); - foo.AddNode("Qux"); + table.AddNode("[blue]Baz[/]"); + foo.AddNode("Qux"); - var bar = tree.AddNode("[yellow]Bar[/]"); - bar.AddNode(new Calendar(2020, 12) - .AddCalendarEvent(2020, 12, 12) - .HideHeader()); + var bar = tree.AddNode("[yellow]Bar[/]"); + bar.AddNode(new Calendar(2020, 12) + .AddCalendarEvent(2020, 12, 12) + .HideHeader()); - // Return the tree - return tree; - } + // Return the tree + return tree; } } diff --git a/examples/Shared/ColorBox.cs b/examples/Shared/ColorBox.cs index e855f46..ef00787 100644 --- a/examples/Shared/ColorBox.cs +++ b/examples/Shared/ColorBox.cs @@ -2,123 +2,122 @@ using System; using System.Collections.Generic; using Spectre.Console.Rendering; -namespace Spectre.Console.Examples +namespace Spectre.Console.Examples; + +public sealed class ColorBox : Renderable { - public sealed class ColorBox : Renderable + private readonly int _height; + private int? _width; + + public ColorBox(int height) { - private readonly int _height; - private int? _width; + _height = height; + } - public ColorBox(int height) + public ColorBox(int width, int height) + : this(height) + { + _width = width; + } + + protected override Measurement Measure(RenderContext context, int maxWidth) + { + return new Measurement(1, GetWidth(maxWidth)); + } + + protected override IEnumerable Render(RenderContext context, int maxWidth) + { + maxWidth = GetWidth(maxWidth); + + for (var y = 0; y < _height; y++) { - _height = height; + for (var x = 0; x < maxWidth; x++) + { + var h = x / (float)maxWidth; + var l = 0.1f + ((y / (float)_height) * 0.7f); + var (r1, g1, b1) = ColorFromHSL(h, l, 1.0f); + var (r2, g2, b2) = ColorFromHSL(h, l + (0.7f / 10), 1.0f); + + var background = new Color((byte)(r1 * 255), (byte)(g1 * 255), (byte)(b1 * 255)); + var foreground = new Color((byte)(r2 * 255), (byte)(g2 * 255), (byte)(b2 * 255)); + + yield return new Segment("▄", new Style(foreground, background)); + } + + yield return Segment.LineBreak; + } + } + + private int GetWidth(int maxWidth) + { + var width = maxWidth; + if (_width != null) + { + width = Math.Min(_width.Value, width); } - public ColorBox(int width, int height) - : this(height) + return width; + } + + private static (float, float, float) ColorFromHSL(double h, double l, double s) + { + double r = 0, g = 0, b = 0; + if (l != 0) { - _width = width; - } - - protected override Measurement Measure(RenderContext context, int maxWidth) - { - return new Measurement(1, GetWidth(maxWidth)); - } - - protected override IEnumerable Render(RenderContext context, int maxWidth) - { - maxWidth = GetWidth(maxWidth); - - for (var y = 0; y < _height; y++) + if (s == 0) { - for (var x = 0; x < maxWidth; x++) - { - var h = x / (float)maxWidth; - var l = 0.1f + ((y / (float)_height) * 0.7f); - var (r1, g1, b1) = ColorFromHSL(h, l, 1.0f); - var (r2, g2, b2) = ColorFromHSL(h, l + (0.7f / 10), 1.0f); - - var background = new Color((byte)(r1 * 255), (byte)(g1 * 255), (byte)(b1 * 255)); - var foreground = new Color((byte)(r2 * 255), (byte)(g2 * 255), (byte)(b2 * 255)); - - yield return new Segment("▄", new Style(foreground, background)); - } - - yield return Segment.LineBreak; - } - } - - private int GetWidth(int maxWidth) - { - var width = maxWidth; - if (_width != null) - { - width = Math.Min(_width.Value, width); - } - - return width; - } - - private static (float, float, float) ColorFromHSL(double h, double l, double s) - { - double r = 0, g = 0, b = 0; - if (l != 0) - { - if (s == 0) - { - r = g = b = l; - } - else - { - double temp2; - if (l < 0.5) - { - temp2 = l * (1.0 + s); - } - else - { - temp2 = l + s - (l * s); - } - - var temp1 = 2.0 * l - temp2; - - r = GetColorComponent(temp1, temp2, h + 1.0 / 3.0); - g = GetColorComponent(temp1, temp2, h); - b = GetColorComponent(temp1, temp2, h - 1.0 / 3.0); - } - } - - return ((float)r, (float)g, (float)b); - - } - - private static double GetColorComponent(double temp1, double temp2, double temp3) - { - if (temp3 < 0.0) - { - temp3 += 1.0; - } - else if (temp3 > 1.0) - { - temp3 -= 1.0; - } - - if (temp3 < 1.0 / 6.0) - { - return temp1 + (temp2 - temp1) * 6.0 * temp3; - } - else if (temp3 < 0.5) - { - return temp2; - } - else if (temp3 < 2.0 / 3.0) - { - return temp1 + ((temp2 - temp1) * ((2.0 / 3.0) - temp3) * 6.0); + r = g = b = l; } else { - return temp1; + double temp2; + if (l < 0.5) + { + temp2 = l * (1.0 + s); + } + else + { + temp2 = l + s - (l * s); + } + + var temp1 = 2.0 * l - temp2; + + r = GetColorComponent(temp1, temp2, h + 1.0 / 3.0); + g = GetColorComponent(temp1, temp2, h); + b = GetColorComponent(temp1, temp2, h - 1.0 / 3.0); } } + + return ((float)r, (float)g, (float)b); + + } + + private static double GetColorComponent(double temp1, double temp2, double temp3) + { + if (temp3 < 0.0) + { + temp3 += 1.0; + } + else if (temp3 > 1.0) + { + temp3 -= 1.0; + } + + if (temp3 < 1.0 / 6.0) + { + return temp1 + (temp2 - temp1) * 6.0 * temp3; + } + else if (temp3 < 0.5) + { + return temp2; + } + else if (temp3 < 2.0 / 3.0) + { + return temp1 + ((temp2 - temp1) * ((2.0 / 3.0) - temp3) * 6.0); + } + else + { + return temp1; + } } } diff --git a/examples/Shared/Extensions/ColorExtensions.cs b/examples/Shared/Extensions/ColorExtensions.cs index 0322c5b..cdc6657 100644 --- a/examples/Shared/Extensions/ColorExtensions.cs +++ b/examples/Shared/Extensions/ColorExtensions.cs @@ -1,15 +1,14 @@ -namespace Spectre.Console.Examples -{ - public static class ColorExtensions - { - public static Color GetInvertedColor(this Color color) - { - return GetLuminance(color) < 140 ? Color.White : Color.Black; - } +namespace Spectre.Console.Examples; - private static float GetLuminance(this Color color) - { - return (float)((0.2126 * color.R) + (0.7152 * color.G) + (0.0722 * color.B)); - } +public static class ColorExtensions +{ + public static Color GetInvertedColor(this Color color) + { + return GetLuminance(color) < 140 ? Color.White : Color.Black; + } + + private static float GetLuminance(this Color color) + { + return (float)((0.2126 * color.R) + (0.7152 * color.G) + (0.0722 * color.B)); } } diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 29f01dd..90e6027 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -1,7 +1,7 @@ true - 9.0 + 10 true embedded true diff --git a/src/Spectre.Console.Analyzer.Sandbox/Program.cs b/src/Spectre.Console.Analyzer.Sandbox/Program.cs index 2d0cd25..cf927c3 100644 --- a/src/Spectre.Console.Analyzer.Sandbox/Program.cs +++ b/src/Spectre.Console.Analyzer.Sandbox/Program.cs @@ -1,16 +1,15 @@ -namespace Spectre.Console.Analyzer.Sandbox +namespace Spectre.Console.Analyzer.Sandbox; + +/// +/// Sample sandbox for testing out analyzers. +/// +public static class Program { /// - /// Sample sandbox for testing out analyzers. + /// The program's entry point. /// - public static class Program + public static void Main() { - /// - /// The program's entry point. - /// - public static void Main() - { - AnsiConsole.WriteLine("Project is set up with a reference to Spectre.Console.Analyzer"); - } + AnsiConsole.WriteLine("Project is set up with a reference to Spectre.Console.Analyzer"); } } diff --git a/src/Spectre.Console.Analyzer/Analyzers/FavorInstanceAnsiConsoleOverStaticAnalyzer.cs b/src/Spectre.Console.Analyzer/Analyzers/FavorInstanceAnsiConsoleOverStaticAnalyzer.cs index f6a4cde..b65cace 100644 --- a/src/Spectre.Console.Analyzer/Analyzers/FavorInstanceAnsiConsoleOverStaticAnalyzer.cs +++ b/src/Spectre.Console.Analyzer/Analyzers/FavorInstanceAnsiConsoleOverStaticAnalyzer.cs @@ -6,90 +6,89 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Operations; -namespace Spectre.Console.Analyzer +namespace Spectre.Console.Analyzer; + +/// +/// Analyzer to suggest using available instances of AnsiConsole over the static methods. +/// +[DiagnosticAnalyzer(LanguageNames.CSharp)] +public class FavorInstanceAnsiConsoleOverStaticAnalyzer : SpectreAnalyzer { - /// - /// Analyzer to suggest using available instances of AnsiConsole over the static methods. - /// - [DiagnosticAnalyzer(LanguageNames.CSharp)] - public class FavorInstanceAnsiConsoleOverStaticAnalyzer : SpectreAnalyzer + private static readonly DiagnosticDescriptor _diagnosticDescriptor = + Descriptors.S1010_FavorInstanceAnsiConsoleOverStatic; + + /// + public override ImmutableArray SupportedDiagnostics => + ImmutableArray.Create(_diagnosticDescriptor); + + /// + protected override void AnalyzeCompilation(CompilationStartAnalysisContext compilationStartContext) { - private static readonly DiagnosticDescriptor _diagnosticDescriptor = - Descriptors.S1010_FavorInstanceAnsiConsoleOverStatic; + compilationStartContext.RegisterOperationAction( + context => + { + var ansiConsoleType = context.Compilation.GetTypeByMetadataName("Spectre.Console.AnsiConsole"); - /// - public override ImmutableArray SupportedDiagnostics => - ImmutableArray.Create(_diagnosticDescriptor); - - /// - protected override void AnalyzeCompilation(CompilationStartAnalysisContext compilationStartContext) - { - compilationStartContext.RegisterOperationAction( - context => + // if this operation isn't an invocation against one of the System.Console methods + // defined in _methods then we can safely stop analyzing and return; + var invocationOperation = (IInvocationOperation)context.Operation; + if (!Equals(invocationOperation.TargetMethod.ContainingType, ansiConsoleType)) { - var ansiConsoleType = context.Compilation.GetTypeByMetadataName("Spectre.Console.AnsiConsole"); + return; + } - // if this operation isn't an invocation against one of the System.Console methods - // defined in _methods then we can safely stop analyzing and return; - var invocationOperation = (IInvocationOperation)context.Operation; - if (!Equals(invocationOperation.TargetMethod.ContainingType, ansiConsoleType)) - { - return; - } + // if we aren't in a method then it might be too complex for us to handle. + if (!invocationOperation.Syntax.Ancestors().OfType().Any()) + { + return; + } - // if we aren't in a method then it might be too complex for us to handle. - if (!invocationOperation.Syntax.Ancestors().OfType().Any()) - { - return; - } + if (!HasFieldAnsiConsole(invocationOperation.Syntax) && + !HasParameterAnsiConsole(invocationOperation.Syntax)) + { + return; + } - if (!HasFieldAnsiConsole(invocationOperation.Syntax) && - !HasParameterAnsiConsole(invocationOperation.Syntax)) - { - return; - } + var methodSymbol = invocationOperation.TargetMethod; - var methodSymbol = invocationOperation.TargetMethod; + var displayString = SymbolDisplay.ToDisplayString( + methodSymbol, + SymbolDisplayFormat.CSharpShortErrorMessageFormat + .WithParameterOptions(SymbolDisplayParameterOptions.None) + .WithGenericsOptions(SymbolDisplayGenericsOptions.None)); - var displayString = SymbolDisplay.ToDisplayString( - methodSymbol, - SymbolDisplayFormat.CSharpShortErrorMessageFormat - .WithParameterOptions(SymbolDisplayParameterOptions.None) - .WithGenericsOptions(SymbolDisplayGenericsOptions.None)); - - context.ReportDiagnostic( - Diagnostic.Create( - _diagnosticDescriptor, - invocationOperation.Syntax.GetLocation(), - displayString)); - }, OperationKind.Invocation); - } - - private static bool HasParameterAnsiConsole(SyntaxNode syntaxNode) - { - return syntaxNode - .Ancestors().OfType() - .First() - .ParameterList.Parameters - .Any(i => i.Type.NormalizeWhitespace().ToString() == "IAnsiConsole"); - } - - private static bool HasFieldAnsiConsole(SyntaxNode syntaxNode) - { - var isStatic = syntaxNode - .Ancestors() - .OfType() - .First() - .Modifiers.Any(i => i.Kind() == SyntaxKind.StaticKeyword); - - return syntaxNode - .Ancestors().OfType() - .First() - .Members - .OfType() - .Any(i => - i.Declaration.Type.NormalizeWhitespace().ToString() == "IAnsiConsole" && - (!isStatic ^ i.Modifiers.Any(modifier => modifier.Kind() == SyntaxKind.StaticKeyword))); - } + context.ReportDiagnostic( + Diagnostic.Create( + _diagnosticDescriptor, + invocationOperation.Syntax.GetLocation(), + displayString)); + }, OperationKind.Invocation); } -} \ No newline at end of file + + private static bool HasParameterAnsiConsole(SyntaxNode syntaxNode) + { + return syntaxNode + .Ancestors().OfType() + .First() + .ParameterList.Parameters + .Any(i => i.Type.NormalizeWhitespace().ToString() == "IAnsiConsole"); + } + + private static bool HasFieldAnsiConsole(SyntaxNode syntaxNode) + { + var isStatic = syntaxNode + .Ancestors() + .OfType() + .First() + .Modifiers.Any(i => i.Kind() == SyntaxKind.StaticKeyword); + + return syntaxNode + .Ancestors().OfType() + .First() + .Members + .OfType() + .Any(i => + i.Declaration.Type.NormalizeWhitespace().ToString() == "IAnsiConsole" && + (!isStatic ^ i.Modifiers.Any(modifier => modifier.Kind() == SyntaxKind.StaticKeyword))); + } +} diff --git a/src/Spectre.Console.Analyzer/Analyzers/NoConcurrentLiveRenderablesAnalyzer.cs b/src/Spectre.Console.Analyzer/Analyzers/NoConcurrentLiveRenderablesAnalyzer.cs index 479b7f9..8133c50 100644 --- a/src/Spectre.Console.Analyzer/Analyzers/NoConcurrentLiveRenderablesAnalyzer.cs +++ b/src/Spectre.Console.Analyzer/Analyzers/NoConcurrentLiveRenderablesAnalyzer.cs @@ -7,72 +7,71 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Operations; -namespace Spectre.Console.Analyzer +namespace Spectre.Console.Analyzer; + +/// +/// Analyzer to detect calls to live renderables within a live renderable context. +/// +[DiagnosticAnalyzer(LanguageNames.CSharp)] +[Shared] +public class NoConcurrentLiveRenderablesAnalyzer : SpectreAnalyzer { - /// - /// Analyzer to detect calls to live renderables within a live renderable context. - /// - [DiagnosticAnalyzer(LanguageNames.CSharp)] - [Shared] - public class NoConcurrentLiveRenderablesAnalyzer : SpectreAnalyzer + private static readonly DiagnosticDescriptor _diagnosticDescriptor = + Descriptors.S1020_AvoidConcurrentCallsToMultipleLiveRenderables; + + /// + public override ImmutableArray SupportedDiagnostics => + ImmutableArray.Create(_diagnosticDescriptor); + + /// + protected override void AnalyzeCompilation(CompilationStartAnalysisContext compilationStartContext) { - private static readonly DiagnosticDescriptor _diagnosticDescriptor = - Descriptors.S1020_AvoidConcurrentCallsToMultipleLiveRenderables; + compilationStartContext.RegisterOperationAction( + context => + { + var invocationOperation = (IInvocationOperation)context.Operation; + var methodSymbol = invocationOperation.TargetMethod; - /// - public override ImmutableArray SupportedDiagnostics => - ImmutableArray.Create(_diagnosticDescriptor); - - /// - protected override void AnalyzeCompilation(CompilationStartAnalysisContext compilationStartContext) - { - compilationStartContext.RegisterOperationAction( - context => + const string StartMethod = "Start"; + if (methodSymbol.Name != StartMethod) { - var invocationOperation = (IInvocationOperation)context.Operation; - var methodSymbol = invocationOperation.TargetMethod; + return; + } - const string StartMethod = "Start"; - if (methodSymbol.Name != StartMethod) - { - return; - } + var liveTypes = Constants.LiveRenderables + .Select(i => context.Compilation.GetTypeByMetadataName(i)) + .ToImmutableArray(); - var liveTypes = Constants.LiveRenderables - .Select(i => context.Compilation.GetTypeByMetadataName(i)) - .ToImmutableArray(); + if (liveTypes.All(i => !Equals(i, methodSymbol.ContainingType))) + { + return; + } - if (liveTypes.All(i => !Equals(i, methodSymbol.ContainingType))) - { - return; - } + var model = context.Compilation.GetSemanticModel(context.Operation.Syntax.SyntaxTree); + var parentInvocations = invocationOperation + .Syntax.Ancestors() + .OfType() + .Select(i => model.GetOperation(i)) + .OfType() + .ToList(); - var model = context.Compilation.GetSemanticModel(context.Operation.Syntax.SyntaxTree); - var parentInvocations = invocationOperation - .Syntax.Ancestors() - .OfType() - .Select(i => model.GetOperation(i)) - .OfType() - .ToList(); + if (parentInvocations.All(parent => + parent.TargetMethod.Name != StartMethod || !liveTypes.Contains(parent.TargetMethod.ContainingType))) + { + return; + } - if (parentInvocations.All(parent => - parent.TargetMethod.Name != StartMethod || !liveTypes.Contains(parent.TargetMethod.ContainingType))) - { - return; - } + var displayString = SymbolDisplay.ToDisplayString( + methodSymbol, + SymbolDisplayFormat.CSharpShortErrorMessageFormat + .WithParameterOptions(SymbolDisplayParameterOptions.None) + .WithGenericsOptions(SymbolDisplayGenericsOptions.None)); - var displayString = SymbolDisplay.ToDisplayString( - methodSymbol, - SymbolDisplayFormat.CSharpShortErrorMessageFormat - .WithParameterOptions(SymbolDisplayParameterOptions.None) - .WithGenericsOptions(SymbolDisplayGenericsOptions.None)); - - context.ReportDiagnostic( - Diagnostic.Create( - _diagnosticDescriptor, - invocationOperation.Syntax.GetLocation(), - displayString)); - }, OperationKind.Invocation); - } + context.ReportDiagnostic( + Diagnostic.Create( + _diagnosticDescriptor, + invocationOperation.Syntax.GetLocation(), + displayString)); + }, OperationKind.Invocation); } -} \ No newline at end of file +} diff --git a/src/Spectre.Console.Analyzer/Analyzers/NoPromptsDuringLiveRenderablesAnalyzer.cs b/src/Spectre.Console.Analyzer/Analyzers/NoPromptsDuringLiveRenderablesAnalyzer.cs index e782650..4496eab 100644 --- a/src/Spectre.Console.Analyzer/Analyzers/NoPromptsDuringLiveRenderablesAnalyzer.cs +++ b/src/Spectre.Console.Analyzer/Analyzers/NoPromptsDuringLiveRenderablesAnalyzer.cs @@ -7,78 +7,77 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Operations; -namespace Spectre.Console.Analyzer +namespace Spectre.Console.Analyzer; + +/// +/// Analyzer to detect calls to live renderables within a live renderable context. +/// +[DiagnosticAnalyzer(LanguageNames.CSharp)] +[Shared] +public class NoPromptsDuringLiveRenderablesAnalyzer : SpectreAnalyzer { - /// - /// Analyzer to detect calls to live renderables within a live renderable context. - /// - [DiagnosticAnalyzer(LanguageNames.CSharp)] - [Shared] - public class NoPromptsDuringLiveRenderablesAnalyzer : SpectreAnalyzer + private static readonly DiagnosticDescriptor _diagnosticDescriptor = + Descriptors.S1021_AvoidPromptCallsDuringLiveRenderables; + + /// + public override ImmutableArray SupportedDiagnostics => + ImmutableArray.Create(_diagnosticDescriptor); + + /// + protected override void AnalyzeCompilation(CompilationStartAnalysisContext compilationStartContext) { - private static readonly DiagnosticDescriptor _diagnosticDescriptor = - Descriptors.S1021_AvoidPromptCallsDuringLiveRenderables; + compilationStartContext.RegisterOperationAction( + context => + { + // if this operation isn't an invocation against one of the System.Console methods + // defined in _methods then we can safely stop analyzing and return; + var invocationOperation = (IInvocationOperation)context.Operation; + var methodSymbol = invocationOperation.TargetMethod; - /// - public override ImmutableArray SupportedDiagnostics => - ImmutableArray.Create(_diagnosticDescriptor); - - /// - protected override void AnalyzeCompilation(CompilationStartAnalysisContext compilationStartContext) - { - compilationStartContext.RegisterOperationAction( - context => + var promptMethods = ImmutableArray.Create("Ask", "Confirm", "Prompt"); + if (!promptMethods.Contains(methodSymbol.Name)) { - // if this operation isn't an invocation against one of the System.Console methods - // defined in _methods then we can safely stop analyzing and return; - var invocationOperation = (IInvocationOperation)context.Operation; - var methodSymbol = invocationOperation.TargetMethod; + return; + } - var promptMethods = ImmutableArray.Create("Ask", "Confirm", "Prompt"); - if (!promptMethods.Contains(methodSymbol.Name)) - { - return; - } + var ansiConsoleType = context.Compilation.GetTypeByMetadataName("Spectre.Console.AnsiConsole"); + var ansiConsoleExtensionsType = context.Compilation.GetTypeByMetadataName("Spectre.Console.AnsiConsoleExtensions"); - var ansiConsoleType = context.Compilation.GetTypeByMetadataName("Spectre.Console.AnsiConsole"); - var ansiConsoleExtensionsType = context.Compilation.GetTypeByMetadataName("Spectre.Console.AnsiConsoleExtensions"); + if (!Equals(methodSymbol.ContainingType, ansiConsoleType) && !Equals(methodSymbol.ContainingType, ansiConsoleExtensionsType)) + { + return; + } - if (!Equals(methodSymbol.ContainingType, ansiConsoleType) && !Equals(methodSymbol.ContainingType, ansiConsoleExtensionsType)) - { - return; - } + var model = context.Compilation.GetSemanticModel(context.Operation.Syntax.SyntaxTree); + var parentInvocations = invocationOperation + .Syntax.Ancestors() + .OfType() + .Select(i => model.GetOperation(i)) + .OfType() + .ToList(); - var model = context.Compilation.GetSemanticModel(context.Operation.Syntax.SyntaxTree); - var parentInvocations = invocationOperation - .Syntax.Ancestors() - .OfType() - .Select(i => model.GetOperation(i)) - .OfType() - .ToList(); + var liveTypes = Constants.LiveRenderables + .Select(i => context.Compilation.GetTypeByMetadataName(i)) + .ToImmutableArray(); - var liveTypes = Constants.LiveRenderables - .Select(i => context.Compilation.GetTypeByMetadataName(i)) - .ToImmutableArray(); + if (parentInvocations.All(parent => + parent.TargetMethod.Name != "Start" || + !liveTypes.Contains(parent.TargetMethod.ContainingType))) + { + return; + } - if (parentInvocations.All(parent => - parent.TargetMethod.Name != "Start" || - !liveTypes.Contains(parent.TargetMethod.ContainingType))) - { - return; - } + var displayString = SymbolDisplay.ToDisplayString( + methodSymbol, + SymbolDisplayFormat.CSharpShortErrorMessageFormat + .WithParameterOptions(SymbolDisplayParameterOptions.None) + .WithGenericsOptions(SymbolDisplayGenericsOptions.None)); - var displayString = SymbolDisplay.ToDisplayString( - methodSymbol, - SymbolDisplayFormat.CSharpShortErrorMessageFormat - .WithParameterOptions(SymbolDisplayParameterOptions.None) - .WithGenericsOptions(SymbolDisplayGenericsOptions.None)); - - context.ReportDiagnostic( - Diagnostic.Create( - _diagnosticDescriptor, - invocationOperation.Syntax.GetLocation(), - displayString)); - }, OperationKind.Invocation); - } + context.ReportDiagnostic( + Diagnostic.Create( + _diagnosticDescriptor, + invocationOperation.Syntax.GetLocation(), + displayString)); + }, OperationKind.Invocation); } -} \ No newline at end of file +} diff --git a/src/Spectre.Console.Analyzer/Analyzers/SpectreAnalyzer.cs b/src/Spectre.Console.Analyzer/Analyzers/SpectreAnalyzer.cs index 852f021..b5486de 100644 --- a/src/Spectre.Console.Analyzer/Analyzers/SpectreAnalyzer.cs +++ b/src/Spectre.Console.Analyzer/Analyzers/SpectreAnalyzer.cs @@ -1,25 +1,24 @@ using Microsoft.CodeAnalysis.Diagnostics; -namespace Spectre.Console.Analyzer +namespace Spectre.Console.Analyzer; + +/// +/// Base class for Spectre analyzers. +/// +public abstract class SpectreAnalyzer : DiagnosticAnalyzer { - /// - /// Base class for Spectre analyzers. - /// - public abstract class SpectreAnalyzer : DiagnosticAnalyzer + /// + public override void Initialize(AnalysisContext context) { - /// - public override void Initialize(AnalysisContext context) - { - context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); - context.EnableConcurrentExecution(); + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); + context.EnableConcurrentExecution(); - context.RegisterCompilationStartAction(AnalyzeCompilation); - } - - /// - /// Analyze compilation. - /// - /// Compilation Start Analysis Context. - protected abstract void AnalyzeCompilation(CompilationStartAnalysisContext compilationStartContext); + context.RegisterCompilationStartAction(AnalyzeCompilation); } -} \ No newline at end of file + + /// + /// Analyze compilation. + /// + /// Compilation Start Analysis Context. + protected abstract void AnalyzeCompilation(CompilationStartAnalysisContext compilationStartContext); +} diff --git a/src/Spectre.Console.Analyzer/Analyzers/UseSpectreInsteadOfSystemConsoleAnalyzer.cs b/src/Spectre.Console.Analyzer/Analyzers/UseSpectreInsteadOfSystemConsoleAnalyzer.cs index 10c8a73..865c095 100644 --- a/src/Spectre.Console.Analyzer/Analyzers/UseSpectreInsteadOfSystemConsoleAnalyzer.cs +++ b/src/Spectre.Console.Analyzer/Analyzers/UseSpectreInsteadOfSystemConsoleAnalyzer.cs @@ -4,60 +4,59 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Operations; -namespace Spectre.Console.Analyzer +namespace Spectre.Console.Analyzer; + +/// +/// Analyzer to enforce the use of AnsiConsole over System.Console for known methods. +/// +[DiagnosticAnalyzer(LanguageNames.CSharp)] +public class UseSpectreInsteadOfSystemConsoleAnalyzer : SpectreAnalyzer { - /// - /// Analyzer to enforce the use of AnsiConsole over System.Console for known methods. - /// - [DiagnosticAnalyzer(LanguageNames.CSharp)] - public class UseSpectreInsteadOfSystemConsoleAnalyzer : SpectreAnalyzer + private static readonly DiagnosticDescriptor _diagnosticDescriptor = + Descriptors.S1000_UseAnsiConsoleOverSystemConsole; + + private static readonly string[] _methods = { "WriteLine", "Write" }; + + /// + public override ImmutableArray SupportedDiagnostics => + ImmutableArray.Create(_diagnosticDescriptor); + + /// + protected override void AnalyzeCompilation(CompilationStartAnalysisContext compilationStartContext) { - private static readonly DiagnosticDescriptor _diagnosticDescriptor = - Descriptors.S1000_UseAnsiConsoleOverSystemConsole; + compilationStartContext.RegisterOperationAction( + context => + { + // if this operation isn't an invocation against one of the System.Console methods + // defined in _methods then we can safely stop analyzing and return; + var invocationOperation = (IInvocationOperation)context.Operation; - private static readonly string[] _methods = { "WriteLine", "Write" }; - - /// - public override ImmutableArray SupportedDiagnostics => - ImmutableArray.Create(_diagnosticDescriptor); - - /// - protected override void AnalyzeCompilation(CompilationStartAnalysisContext compilationStartContext) - { - compilationStartContext.RegisterOperationAction( - context => + var methodName = System.Array.Find(_methods, i => i.Equals(invocationOperation.TargetMethod.Name)); + if (methodName == null) { - // if this operation isn't an invocation against one of the System.Console methods - // defined in _methods then we can safely stop analyzing and return; - var invocationOperation = (IInvocationOperation)context.Operation; + return; + } - var methodName = System.Array.Find(_methods, i => i.Equals(invocationOperation.TargetMethod.Name)); - if (methodName == null) - { - return; - } + var systemConsoleType = context.Compilation.GetTypeByMetadataName("System.Console"); - var systemConsoleType = context.Compilation.GetTypeByMetadataName("System.Console"); + if (!Equals(invocationOperation.TargetMethod.ContainingType, systemConsoleType)) + { + return; + } - if (!Equals(invocationOperation.TargetMethod.ContainingType, systemConsoleType)) - { - return; - } + var methodSymbol = invocationOperation.TargetMethod; - var methodSymbol = invocationOperation.TargetMethod; + var displayString = SymbolDisplay.ToDisplayString( + methodSymbol, + SymbolDisplayFormat.CSharpShortErrorMessageFormat + .WithParameterOptions(SymbolDisplayParameterOptions.None) + .WithGenericsOptions(SymbolDisplayGenericsOptions.None)); - var displayString = SymbolDisplay.ToDisplayString( - methodSymbol, - SymbolDisplayFormat.CSharpShortErrorMessageFormat - .WithParameterOptions(SymbolDisplayParameterOptions.None) - .WithGenericsOptions(SymbolDisplayGenericsOptions.None)); - - context.ReportDiagnostic( - Diagnostic.Create( - _diagnosticDescriptor, - invocationOperation.Syntax.GetLocation(), - displayString)); - }, OperationKind.Invocation); - } + context.ReportDiagnostic( + Diagnostic.Create( + _diagnosticDescriptor, + invocationOperation.Syntax.GetLocation(), + displayString)); + }, OperationKind.Invocation); } -} \ No newline at end of file +} diff --git a/src/Spectre.Console.Analyzer/Constants.cs b/src/Spectre.Console.Analyzer/Constants.cs index 63b079c..bec402a 100644 --- a/src/Spectre.Console.Analyzer/Constants.cs +++ b/src/Spectre.Console.Analyzer/Constants.cs @@ -1,15 +1,14 @@ -namespace Spectre.Console.Analyzer -{ - internal static class Constants - { - internal const string StaticInstance = "AnsiConsole"; - internal const string SpectreConsole = "Spectre.Console"; +namespace Spectre.Console.Analyzer; - internal static readonly string[] LiveRenderables = - { - "Spectre.Console.LiveDisplay", - "Spectre.Console.Progress", - "Spectre.Console.Status", - }; - } -} \ No newline at end of file +internal static class Constants +{ + internal const string StaticInstance = "AnsiConsole"; + internal const string SpectreConsole = "Spectre.Console"; + + internal static readonly string[] LiveRenderables = + { + "Spectre.Console.LiveDisplay", + "Spectre.Console.Progress", + "Spectre.Console.Status", + }; +} diff --git a/src/Spectre.Console.Analyzer/Descriptors.cs b/src/Spectre.Console.Analyzer/Descriptors.cs index 4cdccda..70b6bc0 100644 --- a/src/Spectre.Console.Analyzer/Descriptors.cs +++ b/src/Spectre.Console.Analyzer/Descriptors.cs @@ -3,77 +3,76 @@ using Microsoft.CodeAnalysis; using static Microsoft.CodeAnalysis.DiagnosticSeverity; using static Spectre.Console.Analyzer.Descriptors.Category; -namespace Spectre.Console.Analyzer +namespace Spectre.Console.Analyzer; + +/// +/// Code analysis descriptors. +/// +public static class Descriptors { - /// - /// Code analysis descriptors. - /// - public static class Descriptors + internal enum Category { - internal enum Category - { - Usage, // 1xxx - } - - private static readonly ConcurrentDictionary _categoryMapping = new(); - - private static DiagnosticDescriptor Rule(string id, string title, Category category, DiagnosticSeverity defaultSeverity, string messageFormat, string? description = null) - { - var helpLink = $"https://spectreconsole.net/analyzer/rules/{id.ToLowerInvariant()}"; - const bool IsEnabledByDefault = true; - return new DiagnosticDescriptor( - id, - title, - messageFormat, - _categoryMapping.GetOrAdd(category, c => c.ToString()), - defaultSeverity, - IsEnabledByDefault, - description, - helpLink); - } - - /// - /// Gets definitions of diagnostics Spectre1000. - /// - public static DiagnosticDescriptor S1000_UseAnsiConsoleOverSystemConsole { get; } = - Rule( - "Spectre1000", - "Use AnsiConsole instead of System.Console", - Usage, - Warning, - "Use AnsiConsole instead of System.Console"); - - /// - /// Gets definitions of diagnostics Spectre1010. - /// - public static DiagnosticDescriptor S1010_FavorInstanceAnsiConsoleOverStatic { get; } = - Rule( - "Spectre1010", - "Favor the use of the instance of AnsiConsole over the static helper.", - Usage, - Info, - "Favor the use of the instance of AnsiConsole over the static helper."); - - /// - /// Gets definitions of diagnostics Spectre1020. - /// - public static DiagnosticDescriptor S1020_AvoidConcurrentCallsToMultipleLiveRenderables { get; } = - Rule( - "Spectre1020", - "Avoid calling other live renderables while a current renderable is running.", - Usage, - Warning, - "Avoid calling other live renderables while a current renderable is running."); - - /// - /// Gets definitions of diagnostics Spectre1020. - /// - public static DiagnosticDescriptor S1021_AvoidPromptCallsDuringLiveRenderables { get; } = - Rule( - "Spectre1021", - "Avoid prompting for input while a current renderable is running.", - Usage, - Warning, - "Avoid prompting for input while a current renderable is running."); + Usage, // 1xxx } -} \ No newline at end of file + + private static readonly ConcurrentDictionary _categoryMapping = new(); + + private static DiagnosticDescriptor Rule(string id, string title, Category category, DiagnosticSeverity defaultSeverity, string messageFormat, string? description = null) + { + var helpLink = $"https://spectreconsole.net/analyzer/rules/{id.ToLowerInvariant()}"; + const bool IsEnabledByDefault = true; + return new DiagnosticDescriptor( + id, + title, + messageFormat, + _categoryMapping.GetOrAdd(category, c => c.ToString()), + defaultSeverity, + IsEnabledByDefault, + description, + helpLink); + } + + /// + /// Gets definitions of diagnostics Spectre1000. + /// + public static DiagnosticDescriptor S1000_UseAnsiConsoleOverSystemConsole { get; } = + Rule( + "Spectre1000", + "Use AnsiConsole instead of System.Console", + Usage, + Warning, + "Use AnsiConsole instead of System.Console"); + + /// + /// Gets definitions of diagnostics Spectre1010. + /// + public static DiagnosticDescriptor S1010_FavorInstanceAnsiConsoleOverStatic { get; } = + Rule( + "Spectre1010", + "Favor the use of the instance of AnsiConsole over the static helper.", + Usage, + Info, + "Favor the use of the instance of AnsiConsole over the static helper."); + + /// + /// Gets definitions of diagnostics Spectre1020. + /// + public static DiagnosticDescriptor S1020_AvoidConcurrentCallsToMultipleLiveRenderables { get; } = + Rule( + "Spectre1020", + "Avoid calling other live renderables while a current renderable is running.", + Usage, + Warning, + "Avoid calling other live renderables while a current renderable is running."); + + /// + /// Gets definitions of diagnostics Spectre1020. + /// + public static DiagnosticDescriptor S1021_AvoidPromptCallsDuringLiveRenderables { get; } = + Rule( + "Spectre1021", + "Avoid prompting for input while a current renderable is running.", + Usage, + Warning, + "Avoid prompting for input while a current renderable is running."); +} diff --git a/src/Spectre.Console.Analyzer/Fixes/CodeActions/SwitchToAnsiConsoleAction.cs b/src/Spectre.Console.Analyzer/Fixes/CodeActions/SwitchToAnsiConsoleAction.cs index d742b23..72dd104 100644 --- a/src/Spectre.Console.Analyzer/Fixes/CodeActions/SwitchToAnsiConsoleAction.cs +++ b/src/Spectre.Console.Analyzer/Fixes/CodeActions/SwitchToAnsiConsoleAction.cs @@ -7,110 +7,109 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; -namespace Spectre.Console.Analyzer.CodeActions +namespace Spectre.Console.Analyzer.CodeActions; + +/// +/// Code action to change calls to System.Console to AnsiConsole. +/// +public class SwitchToAnsiConsoleAction : CodeAction { + private readonly Document _document; + private readonly InvocationExpressionSyntax _originalInvocation; + /// - /// Code action to change calls to System.Console to AnsiConsole. + /// Initializes a new instance of the class. /// - public class SwitchToAnsiConsoleAction : CodeAction + /// Document to change. + /// The method to change. + /// Title of the fix. + public SwitchToAnsiConsoleAction(Document document, InvocationExpressionSyntax originalInvocation, string title) { - private readonly Document _document; - private readonly InvocationExpressionSyntax _originalInvocation; - - /// - /// Initializes a new instance of the class. - /// - /// Document to change. - /// The method to change. - /// Title of the fix. - public SwitchToAnsiConsoleAction(Document document, InvocationExpressionSyntax originalInvocation, string title) - { - _document = document; - _originalInvocation = originalInvocation; - Title = title; - } - - /// - public override string Title { get; } - - /// - public override string EquivalenceKey => Title; - - /// - protected override async Task GetChangedDocumentAsync(CancellationToken cancellationToken) - { - var originalCaller = ((MemberAccessExpressionSyntax)_originalInvocation.Expression).Name.ToString(); - - var syntaxTree = await _document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); - var root = (CompilationUnitSyntax)await syntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false); - - // If there is an ansiConsole passed into the method then we'll use it. - // otherwise we'll check for a field level instance. - // if neither of those exist we'll fall back to the static param. - var ansiConsoleParameterDeclaration = GetAnsiConsoleParameterDeclaration(); - var ansiConsoleFieldIdentifier = GetAnsiConsoleFieldDeclaration(); - var ansiConsoleIdentifier = ansiConsoleParameterDeclaration ?? - ansiConsoleFieldIdentifier ?? - Constants.StaticInstance; - - // Replace the System.Console call with a call to the identifier above. - var newRoot = root.ReplaceNode( - _originalInvocation, - GetImportedSpectreCall(originalCaller, ansiConsoleIdentifier)); - - // If we are calling the static instance and Spectre isn't imported yet we should do so. - if (ansiConsoleIdentifier == Constants.StaticInstance && root.Usings.ToList().All(i => i.Name.ToString() != Constants.SpectreConsole)) - { - newRoot = newRoot.AddUsings(Syntax.SpectreUsing); - } - - return _document.WithSyntaxRoot(newRoot); - } - - private string? GetAnsiConsoleParameterDeclaration() - { - return _originalInvocation - .Ancestors().OfType() - .First() - .ParameterList.Parameters - .FirstOrDefault(i => i.Type.NormalizeWhitespace().ToString() == "IAnsiConsole") - ?.Identifier.Text; - } - - private string? GetAnsiConsoleFieldDeclaration() - { - // let's look to see if our call is in a static method. - // if so we'll only want to look for static IAnsiConsoles - // and vice-versa if we aren't. - var isStatic = _originalInvocation - .Ancestors() - .OfType() - .First() - .Modifiers.Any(i => i.Kind() == SyntaxKind.StaticKeyword); - - return _originalInvocation - .Ancestors().OfType() - .First() - .Members - .OfType() - .FirstOrDefault(i => - i.Declaration.Type.NormalizeWhitespace().ToString() == "IAnsiConsole" && - (!isStatic ^ i.Modifiers.Any(modifier => modifier.Kind() == SyntaxKind.StaticKeyword))) - ?.Declaration.Variables.First().Identifier.Text; - } - - private ExpressionSyntax GetImportedSpectreCall(string originalCaller, string ansiConsoleIdentifier) - { - return ExpressionStatement( - InvocationExpression( - MemberAccessExpression( - SyntaxKind.SimpleMemberAccessExpression, - IdentifierName(ansiConsoleIdentifier), - IdentifierName(originalCaller))) - .WithArgumentList(_originalInvocation.ArgumentList) - .WithTrailingTrivia(_originalInvocation.GetTrailingTrivia()) - .WithLeadingTrivia(_originalInvocation.GetLeadingTrivia())) - .Expression; - } + _document = document; + _originalInvocation = originalInvocation; + Title = title; } -} \ No newline at end of file + + /// + public override string Title { get; } + + /// + public override string EquivalenceKey => Title; + + /// + protected override async Task GetChangedDocumentAsync(CancellationToken cancellationToken) + { + var originalCaller = ((MemberAccessExpressionSyntax)_originalInvocation.Expression).Name.ToString(); + + var syntaxTree = await _document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); + var root = (CompilationUnitSyntax)await syntaxTree.GetRootAsync(cancellationToken).ConfigureAwait(false); + + // If there is an ansiConsole passed into the method then we'll use it. + // otherwise we'll check for a field level instance. + // if neither of those exist we'll fall back to the static param. + var ansiConsoleParameterDeclaration = GetAnsiConsoleParameterDeclaration(); + var ansiConsoleFieldIdentifier = GetAnsiConsoleFieldDeclaration(); + var ansiConsoleIdentifier = ansiConsoleParameterDeclaration ?? + ansiConsoleFieldIdentifier ?? + Constants.StaticInstance; + + // Replace the System.Console call with a call to the identifier above. + var newRoot = root.ReplaceNode( + _originalInvocation, + GetImportedSpectreCall(originalCaller, ansiConsoleIdentifier)); + + // If we are calling the static instance and Spectre isn't imported yet we should do so. + if (ansiConsoleIdentifier == Constants.StaticInstance && root.Usings.ToList().All(i => i.Name.ToString() != Constants.SpectreConsole)) + { + newRoot = newRoot.AddUsings(Syntax.SpectreUsing); + } + + return _document.WithSyntaxRoot(newRoot); + } + + private string? GetAnsiConsoleParameterDeclaration() + { + return _originalInvocation + .Ancestors().OfType() + .First() + .ParameterList.Parameters + .FirstOrDefault(i => i.Type.NormalizeWhitespace().ToString() == "IAnsiConsole") + ?.Identifier.Text; + } + + private string? GetAnsiConsoleFieldDeclaration() + { + // let's look to see if our call is in a static method. + // if so we'll only want to look for static IAnsiConsoles + // and vice-versa if we aren't. + var isStatic = _originalInvocation + .Ancestors() + .OfType() + .First() + .Modifiers.Any(i => i.Kind() == SyntaxKind.StaticKeyword); + + return _originalInvocation + .Ancestors().OfType() + .First() + .Members + .OfType() + .FirstOrDefault(i => + i.Declaration.Type.NormalizeWhitespace().ToString() == "IAnsiConsole" && + (!isStatic ^ i.Modifiers.Any(modifier => modifier.Kind() == SyntaxKind.StaticKeyword))) + ?.Declaration.Variables.First().Identifier.Text; + } + + private ExpressionSyntax GetImportedSpectreCall(string originalCaller, string ansiConsoleIdentifier) + { + return ExpressionStatement( + InvocationExpression( + MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + IdentifierName(ansiConsoleIdentifier), + IdentifierName(originalCaller))) + .WithArgumentList(_originalInvocation.ArgumentList) + .WithTrailingTrivia(_originalInvocation.GetTrailingTrivia()) + .WithLeadingTrivia(_originalInvocation.GetLeadingTrivia())) + .Expression; + } +} diff --git a/src/Spectre.Console.Analyzer/Fixes/FixProviders/StaticAnsiConsoleToInstanceFix.cs b/src/Spectre.Console.Analyzer/Fixes/FixProviders/StaticAnsiConsoleToInstanceFix.cs index 53a8b74..2e8ff8b 100644 --- a/src/Spectre.Console.Analyzer/Fixes/FixProviders/StaticAnsiConsoleToInstanceFix.cs +++ b/src/Spectre.Console.Analyzer/Fixes/FixProviders/StaticAnsiConsoleToInstanceFix.cs @@ -6,30 +6,29 @@ using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CSharp.Syntax; using Spectre.Console.Analyzer.CodeActions; -namespace Spectre.Console.Analyzer.FixProviders +namespace Spectre.Console.Analyzer.FixProviders; + +/// +/// Fix provider to change System.Console calls to AnsiConsole calls. +/// +[ExportCodeFixProvider(LanguageNames.CSharp)] +[Shared] +public class StaticAnsiConsoleToInstanceFix : CodeFixProvider { - /// - /// Fix provider to change System.Console calls to AnsiConsole calls. - /// - [ExportCodeFixProvider(LanguageNames.CSharp)] - [Shared] - public class StaticAnsiConsoleToInstanceFix : CodeFixProvider + /// + public sealed override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create( + Descriptors.S1010_FavorInstanceAnsiConsoleOverStatic.Id); + + /// + public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; + + /// + public override async Task RegisterCodeFixesAsync(CodeFixContext context) { - /// - public sealed override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create( - Descriptors.S1010_FavorInstanceAnsiConsoleOverStatic.Id); - - /// - public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; - - /// - public override async Task RegisterCodeFixesAsync(CodeFixContext context) - { - var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); - var methodDeclaration = root.FindNode(context.Span).FirstAncestorOrSelf(); - context.RegisterCodeFix( - new SwitchToAnsiConsoleAction(context.Document, methodDeclaration, "Convert static AnsiConsole calls to local instance."), - context.Diagnostics); - } + var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); + var methodDeclaration = root.FindNode(context.Span).FirstAncestorOrSelf(); + context.RegisterCodeFix( + new SwitchToAnsiConsoleAction(context.Document, methodDeclaration, "Convert static AnsiConsole calls to local instance."), + context.Diagnostics); } -} \ No newline at end of file +} diff --git a/src/Spectre.Console.Analyzer/Fixes/FixProviders/SystemConsoleToAnsiConsoleFix.cs b/src/Spectre.Console.Analyzer/Fixes/FixProviders/SystemConsoleToAnsiConsoleFix.cs index 530ebe0..7cfdbb3 100644 --- a/src/Spectre.Console.Analyzer/Fixes/FixProviders/SystemConsoleToAnsiConsoleFix.cs +++ b/src/Spectre.Console.Analyzer/Fixes/FixProviders/SystemConsoleToAnsiConsoleFix.cs @@ -6,30 +6,29 @@ using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CSharp.Syntax; using Spectre.Console.Analyzer.CodeActions; -namespace Spectre.Console.Analyzer.FixProviders +namespace Spectre.Console.Analyzer.FixProviders; + +/// +/// Fix provider to change System.Console calls to AnsiConsole calls. +/// +[ExportCodeFixProvider(LanguageNames.CSharp)] +[Shared] +public class SystemConsoleToAnsiConsoleFix : CodeFixProvider { - /// - /// Fix provider to change System.Console calls to AnsiConsole calls. - /// - [ExportCodeFixProvider(LanguageNames.CSharp)] - [Shared] - public class SystemConsoleToAnsiConsoleFix : CodeFixProvider + /// + public sealed override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create( + Descriptors.S1000_UseAnsiConsoleOverSystemConsole.Id); + + /// + public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; + + /// + public override async Task RegisterCodeFixesAsync(CodeFixContext context) { - /// - public sealed override ImmutableArray FixableDiagnosticIds => ImmutableArray.Create( - Descriptors.S1000_UseAnsiConsoleOverSystemConsole.Id); - - /// - public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; - - /// - public override async Task RegisterCodeFixesAsync(CodeFixContext context) - { - var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); - var methodDeclaration = root.FindNode(context.Span).FirstAncestorOrSelf(); - context.RegisterCodeFix( - new SwitchToAnsiConsoleAction(context.Document, methodDeclaration, "Convert static call to AnsiConsole to Spectre.Console.AnsiConsole"), - context.Diagnostics); - } + var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); + var methodDeclaration = root.FindNode(context.Span).FirstAncestorOrSelf(); + context.RegisterCodeFix( + new SwitchToAnsiConsoleAction(context.Document, methodDeclaration, "Convert static call to AnsiConsole to Spectre.Console.AnsiConsole"), + context.Diagnostics); } -} \ No newline at end of file +} diff --git a/src/Spectre.Console.Analyzer/Fixes/Syntax.cs b/src/Spectre.Console.Analyzer/Fixes/Syntax.cs index cc0e6e3..0e3aefd 100644 --- a/src/Spectre.Console.Analyzer/Fixes/Syntax.cs +++ b/src/Spectre.Console.Analyzer/Fixes/Syntax.cs @@ -1,10 +1,9 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; -namespace Spectre.Console.Analyzer +namespace Spectre.Console.Analyzer; + +internal static class Syntax { - internal static class Syntax - { - public static readonly UsingDirectiveSyntax SpectreUsing = UsingDirective(QualifiedName(IdentifierName("Spectre"), IdentifierName("Console"))); - } -} \ No newline at end of file + public static readonly UsingDirectiveSyntax SpectreUsing = UsingDirective(QualifiedName(IdentifierName("Spectre"), IdentifierName("Console"))); +} diff --git a/src/Spectre.Console.ImageSharp/CanvasImage.cs b/src/Spectre.Console.ImageSharp/CanvasImage.cs index feb4bc0..999ad91 100644 --- a/src/Spectre.Console.ImageSharp/CanvasImage.cs +++ b/src/Spectre.Console.ImageSharp/CanvasImage.cs @@ -6,139 +6,138 @@ using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Transforms; using Spectre.Console.Rendering; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Represents a renderable image. +/// +public sealed class CanvasImage : Renderable { + private static readonly IResampler _defaultResampler = KnownResamplers.Bicubic; + /// - /// Represents a renderable image. + /// Gets the image width. /// - public sealed class CanvasImage : Renderable + public int Width => Image.Width; + + /// + /// Gets the image height. + /// + public int Height => Image.Height; + + /// + /// Gets or sets the render width of the canvas. + /// + public int? MaxWidth { get; set; } + + /// + /// Gets or sets the render width of the canvas. + /// + public int PixelWidth { get; set; } = 2; + + /// + /// Gets or sets the that should + /// be used when scaling the image. Defaults to bicubic sampling. + /// + public IResampler? Resampler { get; set; } + + internal SixLabors.ImageSharp.Image Image { get; } + + /// + /// Initializes a new instance of the class. + /// + /// The image filename. + public CanvasImage(string filename) { - private static readonly IResampler _defaultResampler = KnownResamplers.Bicubic; - - /// - /// Gets the image width. - /// - public int Width => Image.Width; - - /// - /// Gets the image height. - /// - public int Height => Image.Height; - - /// - /// Gets or sets the render width of the canvas. - /// - public int? MaxWidth { get; set; } - - /// - /// Gets or sets the render width of the canvas. - /// - public int PixelWidth { get; set; } = 2; - - /// - /// Gets or sets the that should - /// be used when scaling the image. Defaults to bicubic sampling. - /// - public IResampler? Resampler { get; set; } - - internal SixLabors.ImageSharp.Image Image { get; } - - /// - /// Initializes a new instance of the class. - /// - /// The image filename. - public CanvasImage(string filename) - { - Image = SixLabors.ImageSharp.Image.Load(filename); - } - - /// - /// Initializes a new instance of the class. - /// - /// Buffer containing an image. - public CanvasImage(ReadOnlySpan data) - { - Image = SixLabors.ImageSharp.Image.Load(data); - } - - /// - /// Initializes a new instance of the class. - /// - /// Stream containing an image. - public CanvasImage(Stream data) - { - Image = SixLabors.ImageSharp.Image.Load(data); - } - - /// - protected override Measurement Measure(RenderContext context, int maxWidth) - { - if (PixelWidth < 0) - { - throw new InvalidOperationException("Pixel width must be greater than zero."); - } - - var width = MaxWidth ?? Width; - if (maxWidth < width * PixelWidth) - { - return new Measurement(maxWidth, maxWidth); - } - - return new Measurement(width * PixelWidth, width * PixelWidth); - } - - /// - protected override IEnumerable Render(RenderContext context, int maxWidth) - { - var image = Image; - - var width = Width; - var height = Height; - - // Got a max width? - if (MaxWidth != null) - { - height = (int)(height * ((float)MaxWidth.Value) / Width); - width = MaxWidth.Value; - } - - // Exceed the max width when we take pixel width into account? - if (width * PixelWidth > maxWidth) - { - height = (int)(height * (maxWidth / (float)(width * PixelWidth))); - width = maxWidth / PixelWidth; - } - - // Need to rescale the pixel buffer? - if (width != Width || height != Height) - { - var resampler = Resampler ?? _defaultResampler; - image = image.Clone(); // Clone the original image - image.Mutate(i => i.Resize(width, height, resampler)); - } - - var canvas = new Canvas(width, height) - { - MaxWidth = MaxWidth, - PixelWidth = PixelWidth, - Scale = false, - }; - - for (var y = 0; y < image.Height; y++) - { - for (var x = 0; x < image.Width; x++) - { - if (image[x, y].A == 0) - { - continue; - } - - canvas.SetPixel(x, y, new Color( - image[x, y].R, image[x, y].G, image[x, y].B)); - } - } - - return ((IRenderable)canvas).Render(context, maxWidth); - } + Image = SixLabors.ImageSharp.Image.Load(filename); } -} + + /// + /// Initializes a new instance of the class. + /// + /// Buffer containing an image. + public CanvasImage(ReadOnlySpan data) + { + Image = SixLabors.ImageSharp.Image.Load(data); + } + + /// + /// Initializes a new instance of the class. + /// + /// Stream containing an image. + public CanvasImage(Stream data) + { + Image = SixLabors.ImageSharp.Image.Load(data); + } + + /// + protected override Measurement Measure(RenderContext context, int maxWidth) + { + if (PixelWidth < 0) + { + throw new InvalidOperationException("Pixel width must be greater than zero."); + } + + var width = MaxWidth ?? Width; + if (maxWidth < width * PixelWidth) + { + return new Measurement(maxWidth, maxWidth); + } + + return new Measurement(width * PixelWidth, width * PixelWidth); + } + + /// + protected override IEnumerable Render(RenderContext context, int maxWidth) + { + var image = Image; + + var width = Width; + var height = Height; + + // Got a max width? + if (MaxWidth != null) + { + height = (int)(height * ((float)MaxWidth.Value) / Width); + width = MaxWidth.Value; + } + + // Exceed the max width when we take pixel width into account? + if (width * PixelWidth > maxWidth) + { + height = (int)(height * (maxWidth / (float)(width * PixelWidth))); + width = maxWidth / PixelWidth; + } + + // Need to rescale the pixel buffer? + if (width != Width || height != Height) + { + var resampler = Resampler ?? _defaultResampler; + image = image.Clone(); // Clone the original image + image.Mutate(i => i.Resize(width, height, resampler)); + } + + var canvas = new Canvas(width, height) + { + MaxWidth = MaxWidth, + PixelWidth = PixelWidth, + Scale = false, + }; + + for (var y = 0; y < image.Height; y++) + { + for (var x = 0; x < image.Width; x++) + { + if (image[x, y].A == 0) + { + continue; + } + + canvas.SetPixel(x, y, new Color( + image[x, y].R, image[x, y].G, image[x, y].B)); + } + } + + return ((IRenderable)canvas).Render(context, maxWidth); + } +} \ No newline at end of file diff --git a/src/Spectre.Console.ImageSharp/CanvasImageExtensions.cs b/src/Spectre.Console.ImageSharp/CanvasImageExtensions.cs index fa99fe6..0da36c3 100644 --- a/src/Spectre.Console.ImageSharp/CanvasImageExtensions.cs +++ b/src/Spectre.Console.ImageSharp/CanvasImageExtensions.cs @@ -1,135 +1,134 @@ using System; using SixLabors.ImageSharp.Processing; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class CanvasImageExtensions { /// - /// Contains extension methods for . + /// Sets the maximum width of the rendered image. /// - public static class CanvasImageExtensions + /// The canvas image. + /// The maximum width. + /// The same instance so that multiple calls can be chained. + public static CanvasImage MaxWidth(this CanvasImage image, int? maxWidth) { - /// - /// Sets the maximum width of the rendered image. - /// - /// The canvas image. - /// The maximum width. - /// The same instance so that multiple calls can be chained. - public static CanvasImage MaxWidth(this CanvasImage image, int? maxWidth) + if (image is null) { - if (image is null) - { - throw new ArgumentNullException(nameof(image)); - } - - image.MaxWidth = maxWidth; - return image; + throw new ArgumentNullException(nameof(image)); } - /// - /// Disables the maximum width of the rendered image. - /// - /// The canvas image. - /// The same instance so that multiple calls can be chained. - public static CanvasImage NoMaxWidth(this CanvasImage image) - { - if (image is null) - { - throw new ArgumentNullException(nameof(image)); - } - - image.MaxWidth = null; - return image; - } - - /// - /// Sets the pixel width. - /// - /// The canvas image. - /// The pixel width. - /// The same instance so that multiple calls can be chained. - public static CanvasImage PixelWidth(this CanvasImage image, int width) - { - if (image is null) - { - throw new ArgumentNullException(nameof(image)); - } - - image.PixelWidth = width; - return image; - } - - /// - /// Mutates the underlying image. - /// - /// The canvas image. - /// The action that mutates the underlying image. - /// The same instance so that multiple calls can be chained. - public static CanvasImage Mutate(this CanvasImage image, Action action) - { - if (image is null) - { - throw new ArgumentNullException(nameof(image)); - } - - if (action is null) - { - throw new ArgumentNullException(nameof(action)); - } - - image.Image.Mutate(action); - return image; - } - - /// - /// Uses a bicubic sampler that implements the bicubic kernel algorithm W(x). - /// - /// The canvas image. - /// The same instance so that multiple calls can be chained. - public static CanvasImage BicubicResampler(this CanvasImage image) - { - if (image is null) - { - throw new ArgumentNullException(nameof(image)); - } - - image.Resampler = KnownResamplers.Bicubic; - return image; - } - - /// - /// Uses a bilinear sampler. This interpolation algorithm - /// can be used where perfect image transformation with pixel matching is impossible, - /// so that one can calculate and assign appropriate intensity values to pixels. - /// - /// The canvas image. - /// The same instance so that multiple calls can be chained. - public static CanvasImage BilinearResampler(this CanvasImage image) - { - if (image is null) - { - throw new ArgumentNullException(nameof(image)); - } - - image.Resampler = KnownResamplers.Triangle; - return image; - } - - /// - /// Uses a Nearest-Neighbour sampler that implements the nearest neighbor algorithm. - /// This uses a very fast, unscaled filter which will select the closest pixel to - /// the new pixels position. - /// - /// The canvas image. - /// The same instance so that multiple calls can be chained. - public static CanvasImage NearestNeighborResampler(this CanvasImage image) - { - if (image is null) - { - throw new ArgumentNullException(nameof(image)); - } - - image.Resampler = KnownResamplers.NearestNeighbor; - return image; - } + image.MaxWidth = maxWidth; + return image; } -} + + /// + /// Disables the maximum width of the rendered image. + /// + /// The canvas image. + /// The same instance so that multiple calls can be chained. + public static CanvasImage NoMaxWidth(this CanvasImage image) + { + if (image is null) + { + throw new ArgumentNullException(nameof(image)); + } + + image.MaxWidth = null; + return image; + } + + /// + /// Sets the pixel width. + /// + /// The canvas image. + /// The pixel width. + /// The same instance so that multiple calls can be chained. + public static CanvasImage PixelWidth(this CanvasImage image, int width) + { + if (image is null) + { + throw new ArgumentNullException(nameof(image)); + } + + image.PixelWidth = width; + return image; + } + + /// + /// Mutates the underlying image. + /// + /// The canvas image. + /// The action that mutates the underlying image. + /// The same instance so that multiple calls can be chained. + public static CanvasImage Mutate(this CanvasImage image, Action action) + { + if (image is null) + { + throw new ArgumentNullException(nameof(image)); + } + + if (action is null) + { + throw new ArgumentNullException(nameof(action)); + } + + image.Image.Mutate(action); + return image; + } + + /// + /// Uses a bicubic sampler that implements the bicubic kernel algorithm W(x). + /// + /// The canvas image. + /// The same instance so that multiple calls can be chained. + public static CanvasImage BicubicResampler(this CanvasImage image) + { + if (image is null) + { + throw new ArgumentNullException(nameof(image)); + } + + image.Resampler = KnownResamplers.Bicubic; + return image; + } + + /// + /// Uses a bilinear sampler. This interpolation algorithm + /// can be used where perfect image transformation with pixel matching is impossible, + /// so that one can calculate and assign appropriate intensity values to pixels. + /// + /// The canvas image. + /// The same instance so that multiple calls can be chained. + public static CanvasImage BilinearResampler(this CanvasImage image) + { + if (image is null) + { + throw new ArgumentNullException(nameof(image)); + } + + image.Resampler = KnownResamplers.Triangle; + return image; + } + + /// + /// Uses a Nearest-Neighbour sampler that implements the nearest neighbor algorithm. + /// This uses a very fast, unscaled filter which will select the closest pixel to + /// the new pixels position. + /// + /// The canvas image. + /// The same instance so that multiple calls can be chained. + public static CanvasImage NearestNeighborResampler(this CanvasImage image) + { + if (image is null) + { + throw new ArgumentNullException(nameof(image)); + } + + image.Resampler = KnownResamplers.NearestNeighbor; + return image; + } +} \ No newline at end of file diff --git a/src/Spectre.Console.Testing/Cli/CallbackCommandInterceptor.cs b/src/Spectre.Console.Testing/Cli/CallbackCommandInterceptor.cs index a99a09b..cfb96b5 100644 --- a/src/Spectre.Console.Testing/Cli/CallbackCommandInterceptor.cs +++ b/src/Spectre.Console.Testing/Cli/CallbackCommandInterceptor.cs @@ -1,28 +1,27 @@ using System; using Spectre.Console.Cli; -namespace Spectre.Console.Testing +namespace Spectre.Console.Testing; + +/// +/// A that triggers a callback when invoked. +/// +public sealed class CallbackCommandInterceptor : ICommandInterceptor { + private readonly Action _callback; + /// - /// A that triggers a callback when invoked. + /// Initializes a new instance of the class. /// - public sealed class CallbackCommandInterceptor : ICommandInterceptor + /// The callback to call when the interceptor is invoked. + public CallbackCommandInterceptor(Action callback) { - private readonly Action _callback; + _callback = callback ?? throw new ArgumentNullException(nameof(callback)); + } - /// - /// Initializes a new instance of the class. - /// - /// The callback to call when the interceptor is invoked. - public CallbackCommandInterceptor(Action callback) - { - _callback = callback ?? throw new ArgumentNullException(nameof(callback)); - } - - /// - public void Intercept(CommandContext context, CommandSettings settings) - { - _callback(context, settings); - } + /// + public void Intercept(CommandContext context, CommandSettings settings) + { + _callback(context, settings); } } diff --git a/src/Spectre.Console.Testing/Cli/CommandAppFailure.cs b/src/Spectre.Console.Testing/Cli/CommandAppFailure.cs index 21ea0b7..22d9215 100644 --- a/src/Spectre.Console.Testing/Cli/CommandAppFailure.cs +++ b/src/Spectre.Console.Testing/Cli/CommandAppFailure.cs @@ -1,29 +1,28 @@ using System; using Spectre.Console.Cli; -namespace Spectre.Console.Testing +namespace Spectre.Console.Testing; + +/// +/// Represents a runtime failure. +/// +public sealed class CommandAppFailure { /// - /// Represents a runtime failure. + /// Gets the exception that was thrown. /// - public sealed class CommandAppFailure + public Exception Exception { get; } + + /// + /// Gets the console output. + /// + public string Output { get; } + + internal CommandAppFailure(Exception exception, string output) { - /// - /// Gets the exception that was thrown. - /// - public Exception Exception { get; } - - /// - /// Gets the console output. - /// - public string Output { get; } - - internal CommandAppFailure(Exception exception, string output) - { - Exception = exception ?? throw new ArgumentNullException(nameof(exception)); - Output = output.NormalizeLineEndings() - .TrimLines() - .Trim(); - } + Exception = exception ?? throw new ArgumentNullException(nameof(exception)); + Output = output.NormalizeLineEndings() + .TrimLines() + .Trim(); } } diff --git a/src/Spectre.Console.Testing/Cli/CommandAppResult.cs b/src/Spectre.Console.Testing/Cli/CommandAppResult.cs index e877eda..dacedd5 100644 --- a/src/Spectre.Console.Testing/Cli/CommandAppResult.cs +++ b/src/Spectre.Console.Testing/Cli/CommandAppResult.cs @@ -1,43 +1,42 @@ using Spectre.Console.Cli; -namespace Spectre.Console.Testing +namespace Spectre.Console.Testing; + +/// +/// Represents the result of a completed run. +/// +public sealed class CommandAppResult { /// - /// Represents the result of a completed run. + /// Gets the exit code. /// - public sealed class CommandAppResult + public int ExitCode { get; } + + /// + /// Gets the console output. + /// + public string Output { get; } + + /// + /// Gets the command context. + /// + public CommandContext? Context { get; } + + /// + /// Gets the command settings. + /// + public CommandSettings? Settings { get; } + + internal CommandAppResult(int exitCode, string output, CommandContext? context, CommandSettings? settings) { - /// - /// Gets the exit code. - /// - public int ExitCode { get; } + ExitCode = exitCode; + Output = output ?? string.Empty; + Context = context; + Settings = settings; - /// - /// Gets the console output. - /// - public string Output { get; } - - /// - /// Gets the command context. - /// - public CommandContext? Context { get; } - - /// - /// Gets the command settings. - /// - public CommandSettings? Settings { get; } - - internal CommandAppResult(int exitCode, string output, CommandContext? context, CommandSettings? settings) - { - ExitCode = exitCode; - Output = output ?? string.Empty; - Context = context; - Settings = settings; - - Output = Output - .NormalizeLineEndings() - .TrimLines() - .Trim(); - } + Output = Output + .NormalizeLineEndings() + .TrimLines() + .Trim(); } } diff --git a/src/Spectre.Console.Testing/Cli/CommandAppTester.cs b/src/Spectre.Console.Testing/Cli/CommandAppTester.cs index 0cd0840..31f8773 100644 --- a/src/Spectre.Console.Testing/Cli/CommandAppTester.cs +++ b/src/Spectre.Console.Testing/Cli/CommandAppTester.cs @@ -1,135 +1,134 @@ using System; using Spectre.Console.Cli; -namespace Spectre.Console.Testing +namespace Spectre.Console.Testing; + +/// +/// A test harness. +/// +public sealed class CommandAppTester { + private Action? _appConfiguration; + private Action? _configuration; + /// - /// A test harness. + /// Initializes a new instance of the class. /// - public sealed class CommandAppTester + /// The registrar. + public CommandAppTester(ITypeRegistrar? registrar = null) { - private Action? _appConfiguration; - private Action? _configuration; + Registrar = registrar; + } - /// - /// Initializes a new instance of the class. - /// - /// The registrar. - public CommandAppTester(ITypeRegistrar? registrar = null) + /// + /// Gets or sets the Registrar to use in the CommandApp. + /// + public ITypeRegistrar? Registrar { get; set; } + + /// + /// Sets the default command. + /// + /// The default command type. + public void SetDefaultCommand() + where T : class, ICommand + { + _appConfiguration = (app) => app.SetDefaultCommand(); + } + + /// + /// Configures the command application. + /// + /// The configuration action. + public void Configure(Action action) + { + if (_configuration != null) { - Registrar = registrar; + throw new InvalidOperationException("The command app harnest have already been configured."); } - /// - /// Gets or sets the Registrar to use in the CommandApp. - /// - public ITypeRegistrar? Registrar { get; set; } + _configuration = action; + } - /// - /// Sets the default command. - /// - /// The default command type. - public void SetDefaultCommand() - where T : class, ICommand + /// + /// Runs the command application and expects an exception of a specific type to be thrown. + /// + /// The expected exception type. + /// The arguments. + /// The information about the failure. + public CommandAppFailure RunAndCatch(params string[] args) + where T : Exception + { + var console = new TestConsole().Width(int.MaxValue); + + try { - _appConfiguration = (app) => app.SetDefaultCommand(); + Run(args, console, c => c.PropagateExceptions()); + throw new InvalidOperationException("Expected an exception to be thrown, but there was none."); } - - /// - /// Configures the command application. - /// - /// The configuration action. - public void Configure(Action action) + catch (T ex) { - if (_configuration != null) + if (ex is CommandAppException commandAppException && commandAppException.Pretty != null) { - throw new InvalidOperationException("The command app harnest have already been configured."); + console.Write(commandAppException.Pretty); + } + else + { + console.WriteLine(ex.Message); } - _configuration = action; + return new CommandAppFailure(ex, console.Output); } - - /// - /// Runs the command application and expects an exception of a specific type to be thrown. - /// - /// The expected exception type. - /// The arguments. - /// The information about the failure. - public CommandAppFailure RunAndCatch(params string[] args) - where T : Exception + catch (Exception ex) { - var console = new TestConsole().Width(int.MaxValue); - - try - { - Run(args, console, c => c.PropagateExceptions()); - throw new InvalidOperationException("Expected an exception to be thrown, but there was none."); - } - catch (T ex) - { - if (ex is CommandAppException commandAppException && commandAppException.Pretty != null) - { - console.Write(commandAppException.Pretty); - } - else - { - console.WriteLine(ex.Message); - } - - return new CommandAppFailure(ex, console.Output); - } - catch (Exception ex) - { - throw new InvalidOperationException( - $"Expected an exception of type '{typeof(T).FullName}' to be thrown, " - + $"but received {ex.GetType().FullName}."); - } - } - - /// - /// Runs the command application. - /// - /// The arguments. - /// The result. - public CommandAppResult Run(params string[] args) - { - var console = new TestConsole().Width(int.MaxValue); - return Run(args, console); - } - - private CommandAppResult Run(string[] args, TestConsole console, Action? config = null) - { - CommandContext? context = null; - CommandSettings? settings = null; - - var app = new CommandApp(Registrar); - _appConfiguration?.Invoke(app); - - if (_configuration != null) - { - app.Configure(_configuration); - } - - if (config != null) - { - app.Configure(config); - } - - app.Configure(c => c.ConfigureConsole(console)); - app.Configure(c => c.SetInterceptor(new CallbackCommandInterceptor((ctx, s) => - { - context = ctx; - settings = s; - }))); - - var result = app.Run(args); - - var output = console.Output - .NormalizeLineEndings() - .TrimLines() - .Trim(); - - return new CommandAppResult(result, output, context, settings); + throw new InvalidOperationException( + $"Expected an exception of type '{typeof(T).FullName}' to be thrown, " + + $"but received {ex.GetType().FullName}."); } } + + /// + /// Runs the command application. + /// + /// The arguments. + /// The result. + public CommandAppResult Run(params string[] args) + { + var console = new TestConsole().Width(int.MaxValue); + return Run(args, console); + } + + private CommandAppResult Run(string[] args, TestConsole console, Action? config = null) + { + CommandContext? context = null; + CommandSettings? settings = null; + + var app = new CommandApp(Registrar); + _appConfiguration?.Invoke(app); + + if (_configuration != null) + { + app.Configure(_configuration); + } + + if (config != null) + { + app.Configure(config); + } + + app.Configure(c => c.ConfigureConsole(console)); + app.Configure(c => c.SetInterceptor(new CallbackCommandInterceptor((ctx, s) => + { + context = ctx; + settings = s; + }))); + + var result = app.Run(args); + + var output = console.Output + .NormalizeLineEndings() + .TrimLines() + .Trim(); + + return new CommandAppResult(result, output, context, settings); + } } diff --git a/src/Spectre.Console.Testing/Cli/TypeRegistrarBaseTests.cs b/src/Spectre.Console.Testing/Cli/TypeRegistrarBaseTests.cs index 8980a98..67cc4f5 100644 --- a/src/Spectre.Console.Testing/Cli/TypeRegistrarBaseTests.cs +++ b/src/Spectre.Console.Testing/Cli/TypeRegistrarBaseTests.cs @@ -1,191 +1,190 @@ using System; using Spectre.Console.Cli; -namespace Spectre.Console.Testing +namespace Spectre.Console.Testing; + +/// +/// This is a utility class for implementors of +/// and corresponding . +/// +public sealed class TypeRegistrarBaseTests { + private readonly Func _registrarFactory; + /// - /// This is a utility class for implementors of - /// and corresponding . + /// Initializes a new instance of the class. /// - public sealed class TypeRegistrarBaseTests + /// The factory to create a new, clean to be used for each test. + public TypeRegistrarBaseTests(Func registrarFactory) { - private readonly Func _registrarFactory; + _registrarFactory = registrarFactory; + } - /// - /// Initializes a new instance of the class. - /// - /// The factory to create a new, clean to be used for each test. - public TypeRegistrarBaseTests(Func registrarFactory) + /// + /// Runs all tests. + /// + /// This exception is raised, if a test fails. + public void RunAllTests() + { + var testCases = new Action[] { - _registrarFactory = registrarFactory; - } - - /// - /// Runs all tests. - /// - /// This exception is raised, if a test fails. - public void RunAllTests() - { - var testCases = new Action[] - { RegistrationsCanBeResolved, InstanceRegistrationsCanBeResolved, LazyRegistrationsCanBeResolved, ResolvingNotRegisteredServiceReturnsNull, ResolvingNullTypeReturnsNull, - }; + }; - foreach (var test in testCases) - { - test(_registrarFactory()); - } - } - - private static void ResolvingNullTypeReturnsNull(ITypeRegistrar registrar) + foreach (var test in testCases) { - // Given no registration - var resolver = registrar.Build(); - - try - { - // When - var actual = resolver.Resolve(null); - - // Then - if (actual != null) - { - throw new TestFailedException( - $"Expected the resolver to resolve null, since null was requested as the service type. Actually resolved {actual.GetType().Name}."); - } - } - catch (Exception ex) - { - throw new TestFailedException( - $"Expected the resolver not to throw, but caught {ex.GetType().Name}.", ex); - } - } - - private static void ResolvingNotRegisteredServiceReturnsNull(ITypeRegistrar registrar) - { - // Given no registration - var resolver = registrar.Build(); - - try - { - // When - var actual = resolver.Resolve(typeof(IMockService)); - - // Then - if (actual != null) - { - throw new TestFailedException( - $"Expected the resolver to resolve null, since no service was registered. Actually resolved {actual.GetType().Name}."); - } - } - catch (Exception ex) - { - throw new TestFailedException( - $"Expected the resolver not to throw, but caught {ex.GetType().Name}.", ex); - } - } - - private static void RegistrationsCanBeResolved(ITypeRegistrar registrar) - { - // Given - registrar.Register(typeof(IMockService), typeof(MockService)); - var resolver = registrar.Build(); - - // When - var actual = resolver.Resolve(typeof(IMockService)); - - // Then - if (actual == null) - { - throw new TestFailedException( - $"Expected the resolver to resolve an instance of {nameof(MockService)}. Actually resolved null."); - } - - if (actual is not MockService) - { - throw new TestFailedException( - $"Expected the resolver to resolve an instance of {nameof(MockService)}. Actually resolved {actual.GetType().Name}."); - } - } - - private static void InstanceRegistrationsCanBeResolved(ITypeRegistrar registrar) - { - // Given - var instance = new MockService(); - registrar.RegisterInstance(typeof(IMockService), instance); - var resolver = registrar.Build(); - - // When - var actual = resolver.Resolve(typeof(IMockService)); - - // Then - if (!ReferenceEquals(actual, instance)) - { - throw new TestFailedException( - "Expected the resolver to resolve exactly the registered instance."); - } - } - - private static void LazyRegistrationsCanBeResolved(ITypeRegistrar registrar) - { - // Given - var instance = new MockService(); - var factoryCalled = false; - registrar.RegisterLazy(typeof(IMockService), () => - { - factoryCalled = true; - return instance; - }); - var resolver = registrar.Build(); - - // When - var actual = resolver.Resolve(typeof(IMockService)); - - // Then - if (!factoryCalled) - { - throw new TestFailedException( - "Expected the factory to be called, to resolve the lazy registration."); - } - - if (!ReferenceEquals(actual, instance)) - { - throw new TestFailedException( - "Expected the resolver to return exactly the result of the lazy-registered factory."); - } - } - - /// - /// internal use only. - /// - private interface IMockService - { - } - - private class MockService : IMockService - { - } - - /// - /// Exception, to be raised when a test fails. - /// - public sealed class TestFailedException : Exception - { - /// - public TestFailedException(string message) - : base(message) - { - } - - /// - public TestFailedException(string message, Exception inner) - : base(message, inner) - { - } + test(_registrarFactory()); } } -} \ No newline at end of file + + private static void ResolvingNullTypeReturnsNull(ITypeRegistrar registrar) + { + // Given no registration + var resolver = registrar.Build(); + + try + { + // When + var actual = resolver.Resolve(null); + + // Then + if (actual != null) + { + throw new TestFailedException( + $"Expected the resolver to resolve null, since null was requested as the service type. Actually resolved {actual.GetType().Name}."); + } + } + catch (Exception ex) + { + throw new TestFailedException( + $"Expected the resolver not to throw, but caught {ex.GetType().Name}.", ex); + } + } + + private static void ResolvingNotRegisteredServiceReturnsNull(ITypeRegistrar registrar) + { + // Given no registration + var resolver = registrar.Build(); + + try + { + // When + var actual = resolver.Resolve(typeof(IMockService)); + + // Then + if (actual != null) + { + throw new TestFailedException( + $"Expected the resolver to resolve null, since no service was registered. Actually resolved {actual.GetType().Name}."); + } + } + catch (Exception ex) + { + throw new TestFailedException( + $"Expected the resolver not to throw, but caught {ex.GetType().Name}.", ex); + } + } + + private static void RegistrationsCanBeResolved(ITypeRegistrar registrar) + { + // Given + registrar.Register(typeof(IMockService), typeof(MockService)); + var resolver = registrar.Build(); + + // When + var actual = resolver.Resolve(typeof(IMockService)); + + // Then + if (actual == null) + { + throw new TestFailedException( + $"Expected the resolver to resolve an instance of {nameof(MockService)}. Actually resolved null."); + } + + if (actual is not MockService) + { + throw new TestFailedException( + $"Expected the resolver to resolve an instance of {nameof(MockService)}. Actually resolved {actual.GetType().Name}."); + } + } + + private static void InstanceRegistrationsCanBeResolved(ITypeRegistrar registrar) + { + // Given + var instance = new MockService(); + registrar.RegisterInstance(typeof(IMockService), instance); + var resolver = registrar.Build(); + + // When + var actual = resolver.Resolve(typeof(IMockService)); + + // Then + if (!ReferenceEquals(actual, instance)) + { + throw new TestFailedException( + "Expected the resolver to resolve exactly the registered instance."); + } + } + + private static void LazyRegistrationsCanBeResolved(ITypeRegistrar registrar) + { + // Given + var instance = new MockService(); + var factoryCalled = false; + registrar.RegisterLazy(typeof(IMockService), () => + { + factoryCalled = true; + return instance; + }); + var resolver = registrar.Build(); + + // When + var actual = resolver.Resolve(typeof(IMockService)); + + // Then + if (!factoryCalled) + { + throw new TestFailedException( + "Expected the factory to be called, to resolve the lazy registration."); + } + + if (!ReferenceEquals(actual, instance)) + { + throw new TestFailedException( + "Expected the resolver to return exactly the result of the lazy-registered factory."); + } + } + + /// + /// internal use only. + /// + private interface IMockService + { + } + + private class MockService : IMockService + { + } + + /// + /// Exception, to be raised when a test fails. + /// + public sealed class TestFailedException : Exception + { + /// + public TestFailedException(string message) + : base(message) + { + } + + /// + public TestFailedException(string message, Exception inner) + : base(message, inner) + { + } + } +} diff --git a/src/Spectre.Console.Testing/Extensions/StringExtensions.cs b/src/Spectre.Console.Testing/Extensions/StringExtensions.cs index 5f12b72..68aa3fb 100644 --- a/src/Spectre.Console.Testing/Extensions/StringExtensions.cs +++ b/src/Spectre.Console.Testing/Extensions/StringExtensions.cs @@ -1,47 +1,46 @@ using System.Collections.Generic; -namespace Spectre.Console.Testing +namespace Spectre.Console.Testing; + +/// +/// Contains extensions for . +/// +public static class StringExtensions { /// - /// Contains extensions for . + /// Returns a new string with all lines trimmed of trailing whitespace. /// - public static class StringExtensions + /// The string to trim. + /// A new string with all lines trimmed of trailing whitespace. + public static string TrimLines(this string value) { - /// - /// Returns a new string with all lines trimmed of trailing whitespace. - /// - /// The string to trim. - /// A new string with all lines trimmed of trailing whitespace. - public static string TrimLines(this string value) + if (value is null) { - if (value is null) - { - return string.Empty; - } - - var result = new List(); - foreach (var line in value.NormalizeLineEndings().Split(new[] { '\n' })) - { - result.Add(line.TrimEnd()); - } - - return string.Join("\n", result); - } - - /// - /// Returns a new string with normalized line endings. - /// - /// The string to normalize line endings for. - /// A new string with normalized line endings. - public static string NormalizeLineEndings(this string value) - { - if (value != null) - { - value = value.Replace("\r\n", "\n"); - return value.Replace("\r", string.Empty); - } - return string.Empty; } + + var result = new List(); + foreach (var line in value.NormalizeLineEndings().Split(new[] { '\n' })) + { + result.Add(line.TrimEnd()); + } + + return string.Join("\n", result); + } + + /// + /// Returns a new string with normalized line endings. + /// + /// The string to normalize line endings for. + /// A new string with normalized line endings. + public static string NormalizeLineEndings(this string value) + { + if (value != null) + { + value = value.Replace("\r\n", "\n"); + return value.Replace("\r", string.Empty); + } + + return string.Empty; } } diff --git a/src/Spectre.Console.Testing/Extensions/StyleExtensions.cs b/src/Spectre.Console.Testing/Extensions/StyleExtensions.cs index bcf3627..a4f392f 100644 --- a/src/Spectre.Console.Testing/Extensions/StyleExtensions.cs +++ b/src/Spectre.Console.Testing/Extensions/StyleExtensions.cs @@ -1,25 +1,24 @@ -namespace Spectre.Console.Testing +namespace Spectre.Console.Testing; + +/// +/// Contains extensions for . +/// +public static class StyleExtensions { /// - /// Contains extensions for . + /// Sets the foreground or background color of the specified style. /// - public static class StyleExtensions + /// The style. + /// The color. + /// Whether or not to set the foreground color. + /// The same instance so that multiple calls can be chained. + public static Style SetColor(this Style style, Color color, bool foreground) { - /// - /// Sets the foreground or background color of the specified style. - /// - /// The style. - /// The color. - /// Whether or not to set the foreground color. - /// The same instance so that multiple calls can be chained. - public static Style SetColor(this Style style, Color color, bool foreground) + if (foreground) { - if (foreground) - { - return style.Foreground(color); - } - - return style.Background(color); + return style.Foreground(color); } + + return style.Background(color); } } diff --git a/src/Spectre.Console.Testing/Internal/NoopCursor.cs b/src/Spectre.Console.Testing/Internal/NoopCursor.cs index 6980bcc..67b7379 100644 --- a/src/Spectre.Console.Testing/Internal/NoopCursor.cs +++ b/src/Spectre.Console.Testing/Internal/NoopCursor.cs @@ -1,17 +1,16 @@ -namespace Spectre.Console.Testing +namespace Spectre.Console.Testing; + +internal sealed class NoopCursor : IAnsiConsoleCursor { - internal sealed class NoopCursor : IAnsiConsoleCursor + public void Move(CursorDirection direction, int steps) { - public void Move(CursorDirection direction, int steps) - { - } + } - public void SetPosition(int column, int line) - { - } + public void SetPosition(int column, int line) + { + } - public void Show(bool show) - { - } + public void Show(bool show) + { } } diff --git a/src/Spectre.Console.Testing/Internal/NoopExclusivityMode.cs b/src/Spectre.Console.Testing/Internal/NoopExclusivityMode.cs index dd5aab5..ec7be80 100644 --- a/src/Spectre.Console.Testing/Internal/NoopExclusivityMode.cs +++ b/src/Spectre.Console.Testing/Internal/NoopExclusivityMode.cs @@ -1,18 +1,17 @@ using System; using System.Threading.Tasks; -namespace Spectre.Console.Testing -{ - internal sealed class NoopExclusivityMode : IExclusivityMode - { - public T Run(Func func) - { - return func(); - } +namespace Spectre.Console.Testing; - public async Task RunAsync(Func> func) - { - return await func().ConfigureAwait(false); - } +internal sealed class NoopExclusivityMode : IExclusivityMode +{ + public T Run(Func func) + { + return func(); + } + + public async Task RunAsync(Func> func) + { + return await func().ConfigureAwait(false); } } diff --git a/src/Spectre.Console.Testing/TestCapabilities.cs b/src/Spectre.Console.Testing/TestCapabilities.cs index 90ca551..749005d 100644 --- a/src/Spectre.Console.Testing/TestCapabilities.cs +++ b/src/Spectre.Console.Testing/TestCapabilities.cs @@ -1,40 +1,39 @@ using Spectre.Console.Rendering; -namespace Spectre.Console.Testing +namespace Spectre.Console.Testing; + +/// +/// Represents fake capabilities useful in tests. +/// +public sealed class TestCapabilities : 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 IsTerminal { get; set; } + + /// + public bool Interactive { get; set; } + + /// + public bool Unicode { get; set; } + /// - /// Represents fake capabilities useful in tests. + /// Creates a with the same capabilities as this instace. /// - public sealed class TestCapabilities : IReadOnlyCapabilities + /// A with the same capabilities as this instace. + public RenderContext CreateRenderContext() { - /// - public ColorSystem ColorSystem { get; set; } = ColorSystem.TrueColor; - - /// - public bool Ansi { get; set; } - - /// - public bool Links { get; set; } - - /// - public bool Legacy { get; set; } - - /// - public bool IsTerminal { get; set; } - - /// - public bool Interactive { get; set; } - - /// - public bool Unicode { get; set; } - - /// - /// Creates a with the same capabilities as this instace. - /// - /// A with the same capabilities as this instace. - public RenderContext CreateRenderContext() - { - return new RenderContext(this); - } + return new RenderContext(this); } } diff --git a/src/Spectre.Console.Testing/TestConsole.cs b/src/Spectre.Console.Testing/TestConsole.cs index 6ccff15..d40c01f 100644 --- a/src/Spectre.Console.Testing/TestConsole.cs +++ b/src/Spectre.Console.Testing/TestConsole.cs @@ -3,120 +3,119 @@ using System.Collections.Generic; using System.IO; using Spectre.Console.Rendering; -namespace Spectre.Console.Testing +namespace Spectre.Console.Testing; + +/// +/// A testable console. +/// +public sealed class TestConsole : IAnsiConsole, IDisposable { + private readonly IAnsiConsole _console; + private readonly StringWriter _writer; + private IAnsiConsoleCursor? _cursor; + + /// + public Profile Profile => _console.Profile; + + /// + public IExclusivityMode ExclusivityMode => _console.ExclusivityMode; + /// - /// A testable console. + /// Gets the console input. /// - public sealed class TestConsole : IAnsiConsole, IDisposable + public TestConsoleInput Input { get; } + + /// + public RenderPipeline Pipeline => _console.Pipeline; + + /// + public IAnsiConsoleCursor Cursor => _cursor ?? _console.Cursor; + + /// + IAnsiConsoleInput IAnsiConsole.Input => Input; + + /// + /// Gets the console output. + /// + public string Output => _writer.ToString(); + + /// + /// Gets the console output lines. + /// + public IReadOnlyList Lines => Output.NormalizeLineEndings().TrimEnd('\n').Split(new char[] { '\n' }); + + /// + /// Gets or sets a value indicating whether or not VT/ANSI sequences + /// should be emitted to the console. + /// + public bool EmitAnsiSequences { get; set; } + + /// + /// Initializes a new instance of the class. + /// + public TestConsole() { - private readonly IAnsiConsole _console; - private readonly StringWriter _writer; - private IAnsiConsoleCursor? _cursor; + _writer = new StringWriter(); + _cursor = new NoopCursor(); - /// - public Profile Profile => _console.Profile; + Input = new TestConsoleInput(); + EmitAnsiSequences = false; - /// - public IExclusivityMode ExclusivityMode => _console.ExclusivityMode; - - /// - /// Gets the console input. - /// - public TestConsoleInput Input { get; } - - /// - public RenderPipeline Pipeline => _console.Pipeline; - - /// - public IAnsiConsoleCursor Cursor => _cursor ?? _console.Cursor; - - /// - IAnsiConsoleInput IAnsiConsole.Input => Input; - - /// - /// Gets the console output. - /// - public string Output => _writer.ToString(); - - /// - /// Gets the console output lines. - /// - public IReadOnlyList Lines => Output.NormalizeLineEndings().TrimEnd('\n').Split(new char[] { '\n' }); - - /// - /// Gets or sets a value indicating whether or not VT/ANSI sequences - /// should be emitted to the console. - /// - public bool EmitAnsiSequences { get; set; } - - /// - /// Initializes a new instance of the class. - /// - public TestConsole() + var factory = new AnsiConsoleFactory(); + _console = factory.Create(new AnsiConsoleSettings { - _writer = new StringWriter(); - _cursor = new NoopCursor(); - - Input = new TestConsoleInput(); - EmitAnsiSequences = false; - - var factory = new AnsiConsoleFactory(); - _console = factory.Create(new AnsiConsoleSettings + Ansi = AnsiSupport.Yes, + ColorSystem = (ColorSystemSupport)ColorSystem.TrueColor, + Out = new AnsiConsoleOutput(_writer), + Interactive = InteractionSupport.No, + ExclusivityMode = new NoopExclusivityMode(), + Enrichment = new ProfileEnrichment { - Ansi = AnsiSupport.Yes, - ColorSystem = (ColorSystemSupport)ColorSystem.TrueColor, - Out = new AnsiConsoleOutput(_writer), - Interactive = InteractionSupport.No, - ExclusivityMode = new NoopExclusivityMode(), - Enrichment = new ProfileEnrichment + UseDefaultEnrichers = false, + }, + }); + + _console.Profile.Width = 80; + _console.Profile.Height = 24; + _console.Profile.Capabilities.Ansi = true; + _console.Profile.Capabilities.Unicode = true; + } + + /// + public void Dispose() + { + _writer.Dispose(); + } + + /// + public void Clear(bool home) + { + _console.Clear(home); + } + + /// + public void Write(IRenderable renderable) + { + if (EmitAnsiSequences) + { + _console.Write(renderable); + } + else + { + foreach (var segment in renderable.GetSegments(this)) + { + if (segment.IsControlCode) { - UseDefaultEnrichers = false, - }, - }); - - _console.Profile.Width = 80; - _console.Profile.Height = 24; - _console.Profile.Capabilities.Ansi = true; - _console.Profile.Capabilities.Unicode = true; - } - - /// - public void Dispose() - { - _writer.Dispose(); - } - - /// - public void Clear(bool home) - { - _console.Clear(home); - } - - /// - public void Write(IRenderable renderable) - { - if (EmitAnsiSequences) - { - _console.Write(renderable); - } - else - { - foreach (var segment in renderable.GetSegments(this)) - { - if (segment.IsControlCode) - { - continue; - } - - Profile.Out.Writer.Write(segment.Text); + continue; } - } - } - internal void SetCursor(IAnsiConsoleCursor? cursor) - { - _cursor = cursor; + Profile.Out.Writer.Write(segment.Text); + } } } + + internal void SetCursor(IAnsiConsoleCursor? cursor) + { + _cursor = cursor; + } } diff --git a/src/Spectre.Console.Testing/TestConsoleExtensions.cs b/src/Spectre.Console.Testing/TestConsoleExtensions.cs index eb3f441..feeda73 100644 --- a/src/Spectre.Console.Testing/TestConsoleExtensions.cs +++ b/src/Spectre.Console.Testing/TestConsoleExtensions.cs @@ -1,67 +1,66 @@ -namespace Spectre.Console.Testing +namespace Spectre.Console.Testing; + +/// +/// Contains extensions for . +/// +public static class TestConsoleExtensions { /// - /// Contains extensions for . + /// Sets the console's color system. /// - public static class TestConsoleExtensions + /// The console. + /// The color system to use. + /// The same instance so that multiple calls can be chained. + public static TestConsole Colors(this TestConsole console, ColorSystem colors) { - /// - /// Sets the console's color system. - /// - /// The console. - /// The color system to use. - /// The same instance so that multiple calls can be chained. - public static TestConsole Colors(this TestConsole console, ColorSystem colors) - { - console.Profile.Capabilities.ColorSystem = colors; - return console; - } + console.Profile.Capabilities.ColorSystem = colors; + return console; + } - /// - /// Sets whether or not ANSI is supported. - /// - /// The console. - /// Whether or not VT/ANSI control codes are supported. - /// The same instance so that multiple calls can be chained. - public static TestConsole SupportsAnsi(this TestConsole console, bool enable) - { - console.Profile.Capabilities.Ansi = enable; - return console; - } + /// + /// Sets whether or not ANSI is supported. + /// + /// The console. + /// Whether or not VT/ANSI control codes are supported. + /// The same instance so that multiple calls can be chained. + public static TestConsole SupportsAnsi(this TestConsole console, bool enable) + { + console.Profile.Capabilities.Ansi = enable; + return console; + } - /// - /// Makes the console interactive. - /// - /// The console. - /// The same instance so that multiple calls can be chained. - public static TestConsole Interactive(this TestConsole console) - { - console.Profile.Capabilities.Interactive = true; - return console; - } + /// + /// Makes the console interactive. + /// + /// The console. + /// The same instance so that multiple calls can be chained. + public static TestConsole Interactive(this TestConsole console) + { + console.Profile.Capabilities.Interactive = true; + return console; + } - /// - /// Sets the console width. - /// - /// The console. - /// The console width. - /// The same instance so that multiple calls can be chained. - public static TestConsole Width(this TestConsole console, int width) - { - console.Profile.Width = width; - return console; - } + /// + /// Sets the console width. + /// + /// The console. + /// The console width. + /// The same instance so that multiple calls can be chained. + public static TestConsole Width(this TestConsole console, int width) + { + console.Profile.Width = width; + return console; + } - /// - /// Turns on emitting of VT/ANSI sequences. - /// - /// The console. - /// The same instance so that multiple calls can be chained. - public static TestConsole EmitAnsiSequences(this TestConsole console) - { - console.SetCursor(null); - console.EmitAnsiSequences = true; - return console; - } + /// + /// Turns on emitting of VT/ANSI sequences. + /// + /// The console. + /// The same instance so that multiple calls can be chained. + public static TestConsole EmitAnsiSequences(this TestConsole console) + { + console.SetCursor(null); + console.EmitAnsiSequences = true; + return console; } } diff --git a/src/Spectre.Console.Testing/TestConsoleInput.cs b/src/Spectre.Console.Testing/TestConsoleInput.cs index 1342e29..274bec4 100644 --- a/src/Spectre.Console.Testing/TestConsoleInput.cs +++ b/src/Spectre.Console.Testing/TestConsoleInput.cs @@ -3,90 +3,89 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -namespace Spectre.Console.Testing +namespace Spectre.Console.Testing; + +/// +/// Represents a testable console input mechanism. +/// +public sealed class TestConsoleInput : IAnsiConsoleInput { + private readonly Queue _input; + /// - /// Represents a testable console input mechanism. + /// Initializes a new instance of the class. /// - public sealed class TestConsoleInput : IAnsiConsoleInput + public TestConsoleInput() { - private readonly Queue _input; + _input = new Queue(); + } - /// - /// Initializes a new instance of the class. - /// - public TestConsoleInput() + /// + /// Pushes the specified text to the input queue. + /// + /// The input string. + public void PushText(string input) + { + if (input is null) { - _input = new Queue(); + throw new ArgumentNullException(nameof(input)); } - /// - /// Pushes the specified text to the input queue. - /// - /// The input string. - public void PushText(string input) + foreach (var character in input) { - if (input is null) - { - throw new ArgumentNullException(nameof(input)); - } - - foreach (var character in input) - { - PushCharacter(character); - } - } - - /// - /// Pushes the specified text followed by 'Enter' to the input queue. - /// - /// The input. - public void PushTextWithEnter(string input) - { - PushText(input); - PushKey(ConsoleKey.Enter); - } - - /// - /// Pushes the specified character to the input queue. - /// - /// The input. - public void PushCharacter(char input) - { - var control = char.IsUpper(input); - _input.Enqueue(new ConsoleKeyInfo(input, (ConsoleKey)input, false, false, control)); - } - - /// - /// Pushes the specified key to the input queue. - /// - /// The input. - public void PushKey(ConsoleKey input) - { - _input.Enqueue(new ConsoleKeyInfo((char)input, input, false, false, false)); - } - - /// - public bool IsKeyAvailable() - { - return _input.Count > 0; - } - - /// - public ConsoleKeyInfo? ReadKey(bool intercept) - { - if (_input.Count == 0) - { - throw new InvalidOperationException("No input available."); - } - - return _input.Dequeue(); - } - - /// - public Task ReadKeyAsync(bool intercept, CancellationToken cancellationToken) - { - return Task.FromResult(ReadKey(intercept)); + PushCharacter(character); } } + + /// + /// Pushes the specified text followed by 'Enter' to the input queue. + /// + /// The input. + public void PushTextWithEnter(string input) + { + PushText(input); + PushKey(ConsoleKey.Enter); + } + + /// + /// Pushes the specified character to the input queue. + /// + /// The input. + public void PushCharacter(char input) + { + var control = char.IsUpper(input); + _input.Enqueue(new ConsoleKeyInfo(input, (ConsoleKey)input, false, false, control)); + } + + /// + /// Pushes the specified key to the input queue. + /// + /// The input. + public void PushKey(ConsoleKey input) + { + _input.Enqueue(new ConsoleKeyInfo((char)input, input, false, false, false)); + } + + /// + public bool IsKeyAvailable() + { + return _input.Count > 0; + } + + /// + public ConsoleKeyInfo? ReadKey(bool intercept) + { + if (_input.Count == 0) + { + throw new InvalidOperationException("No input available."); + } + + return _input.Dequeue(); + } + + /// + public Task ReadKeyAsync(bool intercept, CancellationToken cancellationToken) + { + return Task.FromResult(ReadKey(intercept)); + } } diff --git a/src/Spectre.Console/AnsiConsole.Exceptions.cs b/src/Spectre.Console/AnsiConsole.Exceptions.cs index 133fff1..b49a03d 100644 --- a/src/Spectre.Console/AnsiConsole.Exceptions.cs +++ b/src/Spectre.Console/AnsiConsole.Exceptions.cs @@ -1,30 +1,29 @@ using System; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// A console capable of writing ANSI escape sequences. +/// +public static partial class AnsiConsole { /// - /// A console capable of writing ANSI escape sequences. + /// Writes an exception to the console. /// - public static partial class AnsiConsole + /// The exception to write to the console. + /// The exception format options. + public static void WriteException(Exception exception, ExceptionFormats format = ExceptionFormats.Default) { - /// - /// Writes an exception to the console. - /// - /// The exception to write to the console. - /// The exception format options. - public static void WriteException(Exception exception, ExceptionFormats format = ExceptionFormats.Default) - { - Console.WriteException(exception, format); - } - - /// - /// Writes an exception to the console. - /// - /// The exception to write to the console. - /// The exception settings. - public static void WriteException(Exception exception, ExceptionSettings settings) - { - Console.WriteException(exception, settings); - } + Console.WriteException(exception, format); } -} + + /// + /// Writes an exception to the console. + /// + /// The exception to write to the console. + /// The exception settings. + public static void WriteException(Exception exception, ExceptionSettings settings) + { + Console.WriteException(exception, settings); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/AnsiConsole.Live.cs b/src/Spectre.Console/AnsiConsole.Live.cs index 3d12717..4efd7c5 100644 --- a/src/Spectre.Console/AnsiConsole.Live.cs +++ b/src/Spectre.Console/AnsiConsole.Live.cs @@ -1,20 +1,19 @@ using Spectre.Console.Rendering; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// A console capable of writing ANSI escape sequences. +/// +public static partial class AnsiConsole { /// - /// A console capable of writing ANSI escape sequences. + /// Creates a new instance. /// - public static partial class AnsiConsole + /// The target renderable to update. + /// A instance. + public static LiveDisplay Live(IRenderable target) { - /// - /// Creates a new instance. - /// - /// The target renderable to update. - /// A instance. - public static LiveDisplay Live(IRenderable target) - { - return Console.Live(target); - } + return Console.Live(target); } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/AnsiConsole.Markup.cs b/src/Spectre.Console/AnsiConsole.Markup.cs index ab7e1d6..962e7ff 100644 --- a/src/Spectre.Console/AnsiConsole.Markup.cs +++ b/src/Spectre.Console/AnsiConsole.Markup.cs @@ -1,70 +1,69 @@ using System; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// A console capable of writing ANSI escape sequences. +/// +public static partial class AnsiConsole { /// - /// A console capable of writing ANSI escape sequences. + /// Writes the specified markup to the console. /// - public static partial class AnsiConsole + /// The value to write. + public static void Markup(string value) { - /// - /// Writes the specified markup to the console. - /// - /// The value to write. - public static void Markup(string value) - { - Console.Markup(value); - } - - /// - /// Writes the specified markup to the console. - /// - /// A composite format string. - /// An array of objects to write. - public static void Markup(string format, params object[] args) - { - Console.Markup(format, args); - } - - /// - /// Writes the specified markup to the console. - /// - /// An object that supplies culture-specific formatting information. - /// A composite format string. - /// An array of objects to write. - public static void Markup(IFormatProvider provider, string format, params object[] args) - { - Console.Markup(provider, format, args); - } - - /// - /// Writes the specified markup, followed by the current line terminator, to the console. - /// - /// The value to write. - public static void MarkupLine(string value) - { - Console.MarkupLine(value); - } - - /// - /// Writes the specified markup, followed by the current line terminator, to the console. - /// - /// A composite format string. - /// An array of objects to write. - public static void MarkupLine(string format, params object[] args) - { - Console.MarkupLine(format, args); - } - - /// - /// Writes the specified markup, followed by the current line terminator, to the console. - /// - /// An object that supplies culture-specific formatting information. - /// A composite format string. - /// An array of objects to write. - public static void MarkupLine(IFormatProvider provider, string format, params object[] args) - { - Console.MarkupLine(provider, format, args); - } + Console.Markup(value); } -} + + /// + /// Writes the specified markup to the console. + /// + /// A composite format string. + /// An array of objects to write. + public static void Markup(string format, params object[] args) + { + Console.Markup(format, args); + } + + /// + /// Writes the specified markup to the console. + /// + /// An object that supplies culture-specific formatting information. + /// A composite format string. + /// An array of objects to write. + public static void Markup(IFormatProvider provider, string format, params object[] args) + { + Console.Markup(provider, format, args); + } + + /// + /// Writes the specified markup, followed by the current line terminator, to the console. + /// + /// The value to write. + public static void MarkupLine(string value) + { + Console.MarkupLine(value); + } + + /// + /// Writes the specified markup, followed by the current line terminator, to the console. + /// + /// A composite format string. + /// An array of objects to write. + public static void MarkupLine(string format, params object[] args) + { + Console.MarkupLine(format, args); + } + + /// + /// Writes the specified markup, followed by the current line terminator, to the console. + /// + /// An object that supplies culture-specific formatting information. + /// A composite format string. + /// An array of objects to write. + public static void MarkupLine(IFormatProvider provider, string format, params object[] args) + { + Console.MarkupLine(provider, format, args); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/AnsiConsole.Progress.cs b/src/Spectre.Console/AnsiConsole.Progress.cs index c73d592..144c923 100644 --- a/src/Spectre.Console/AnsiConsole.Progress.cs +++ b/src/Spectre.Console/AnsiConsole.Progress.cs @@ -1,26 +1,25 @@ -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// A console capable of writing ANSI escape sequences. +/// +public static partial class AnsiConsole { /// - /// A console capable of writing ANSI escape sequences. + /// Creates a new instance. /// - public static partial class AnsiConsole + /// A instance. + public static Progress Progress() { - /// - /// Creates a new instance. - /// - /// A instance. - public static Progress Progress() - { - return Console.Progress(); - } - - /// - /// Creates a new instance. - /// - /// A instance. - public static Status Status() - { - return Console.Status(); - } + return Console.Progress(); } -} + + /// + /// Creates a new instance. + /// + /// A instance. + public static Status Status() + { + return Console.Status(); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/AnsiConsole.Prompt.cs b/src/Spectre.Console/AnsiConsole.Prompt.cs index a0d7a6b..2bd5ba2 100644 --- a/src/Spectre.Console/AnsiConsole.Prompt.cs +++ b/src/Spectre.Console/AnsiConsole.Prompt.cs @@ -1,66 +1,65 @@ using System; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// A console capable of writing ANSI escape sequences. +/// +public static partial class AnsiConsole { /// - /// A console capable of writing ANSI escape sequences. + /// Displays a prompt to the user. /// - public static partial class AnsiConsole + /// The prompt result type. + /// The prompt to display. + /// The prompt input result. + public static T Prompt(IPrompt prompt) { - /// - /// Displays a prompt to the user. - /// - /// The prompt result type. - /// The prompt to display. - /// The prompt input result. - public static T Prompt(IPrompt prompt) + if (prompt is null) { - if (prompt is null) - { - throw new ArgumentNullException(nameof(prompt)); - } - - return prompt.Show(Console); + throw new ArgumentNullException(nameof(prompt)); } - /// - /// Displays a prompt to the user. - /// - /// The prompt result type. - /// The prompt markup text. - /// The prompt input result. - public static T Ask(string prompt) - { - return new TextPrompt(prompt).Show(Console); - } - - /// - /// Displays a prompt to the user with a given default. - /// - /// The prompt result type. - /// The prompt markup text. - /// The default value. - /// The prompt input result. - public static T Ask(string prompt, T defaultValue) - { - return new TextPrompt(prompt) - .DefaultValue(defaultValue) - .Show(Console); - } - - /// - /// Displays a prompt with two choices, yes or no. - /// - /// The prompt markup text. - /// Specifies the default answer. - /// true if the user selected "yes", otherwise false. - public static bool Confirm(string prompt, bool defaultValue = true) - { - return new ConfirmationPrompt(prompt) - { - DefaultValue = defaultValue, - } - .Show(Console); - } + return prompt.Show(Console); } -} + + /// + /// Displays a prompt to the user. + /// + /// The prompt result type. + /// The prompt markup text. + /// The prompt input result. + public static T Ask(string prompt) + { + return new TextPrompt(prompt).Show(Console); + } + + /// + /// Displays a prompt to the user with a given default. + /// + /// The prompt result type. + /// The prompt markup text. + /// The default value. + /// The prompt input result. + public static T Ask(string prompt, T defaultValue) + { + return new TextPrompt(prompt) + .DefaultValue(defaultValue) + .Show(Console); + } + + /// + /// Displays a prompt with two choices, yes or no. + /// + /// The prompt markup text. + /// Specifies the default answer. + /// true if the user selected "yes", otherwise false. + public static bool Confirm(string prompt, bool defaultValue = true) + { + return new ConfirmationPrompt(prompt) + { + DefaultValue = defaultValue, + } + .Show(Console); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/AnsiConsole.Recording.cs b/src/Spectre.Console/AnsiConsole.Recording.cs index 401acd8..a28c89f 100644 --- a/src/Spectre.Console/AnsiConsole.Recording.cs +++ b/src/Spectre.Console/AnsiConsole.Recording.cs @@ -1,70 +1,69 @@ using System; using Spectre.Console.Rendering; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// A console capable of writing ANSI escape sequences. +/// +public static partial class AnsiConsole { /// - /// A console capable of writing ANSI escape sequences. + /// Starts recording the console output. /// - public static partial class AnsiConsole + public static void Record() { - /// - /// Starts recording the console output. - /// - public static void Record() + if (_recorder == null) { - if (_recorder == null) - { - _recorder = new Recorder(Console); - } - } - - /// - /// Exports all recorded console output as text. - /// - /// The recorded output as text. - public static string ExportText() - { - if (_recorder == null) - { - throw new InvalidOperationException("Cannot export text since a recording hasn't been started."); - } - - return _recorder.ExportText(); - } - - /// - /// Exports all recorded console output as HTML text. - /// - /// The recorded output as HTML text. - public static string ExportHtml() - { - if (_recorder == null) - { - throw new InvalidOperationException("Cannot export HTML since a recording hasn't been started."); - } - - return _recorder.ExportHtml(); - } - - /// - /// Exports all recorded console output using a custom encoder. - /// - /// The encoder to use. - /// The recorded output. - public static string ExportCustom(IAnsiConsoleEncoder encoder) - { - if (_recorder == null) - { - throw new InvalidOperationException("Cannot export HTML since a recording hasn't been started."); - } - - if (encoder is null) - { - throw new ArgumentNullException(nameof(encoder)); - } - - return _recorder.Export(encoder); + _recorder = new Recorder(Console); } } -} + + /// + /// Exports all recorded console output as text. + /// + /// The recorded output as text. + public static string ExportText() + { + if (_recorder == null) + { + throw new InvalidOperationException("Cannot export text since a recording hasn't been started."); + } + + return _recorder.ExportText(); + } + + /// + /// Exports all recorded console output as HTML text. + /// + /// The recorded output as HTML text. + public static string ExportHtml() + { + if (_recorder == null) + { + throw new InvalidOperationException("Cannot export HTML since a recording hasn't been started."); + } + + return _recorder.ExportHtml(); + } + + /// + /// Exports all recorded console output using a custom encoder. + /// + /// The encoder to use. + /// The recorded output. + public static string ExportCustom(IAnsiConsoleEncoder encoder) + { + if (_recorder == null) + { + throw new InvalidOperationException("Cannot export HTML since a recording hasn't been started."); + } + + if (encoder is null) + { + throw new ArgumentNullException(nameof(encoder)); + } + + return _recorder.Export(encoder); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/AnsiConsole.Rendering.cs b/src/Spectre.Console/AnsiConsole.Rendering.cs index 9423f56..0ede6fd 100644 --- a/src/Spectre.Console/AnsiConsole.Rendering.cs +++ b/src/Spectre.Console/AnsiConsole.Rendering.cs @@ -1,35 +1,34 @@ using System; using Spectre.Console.Rendering; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// A console capable of writing ANSI escape sequences. +/// +public static partial class AnsiConsole { /// - /// A console capable of writing ANSI escape sequences. + /// Renders the specified object to the console. /// - public static partial class AnsiConsole + /// The object to render. + [Obsolete("Consider using AnsiConsole.Write instead.")] + public static void Render(IRenderable renderable) { - /// - /// Renders the specified object to the console. - /// - /// The object to render. - [Obsolete("Consider using AnsiConsole.Write instead.")] - public static void Render(IRenderable renderable) - { - Write(renderable); - } - - /// - /// Renders the specified to the console. - /// - /// The object to render. - public static void Write(IRenderable renderable) - { - if (renderable is null) - { - throw new ArgumentNullException(nameof(renderable)); - } - - Console.Write(renderable); - } + Write(renderable); } -} + + /// + /// Renders the specified to the console. + /// + /// The object to render. + public static void Write(IRenderable renderable) + { + if (renderable is null) + { + throw new ArgumentNullException(nameof(renderable)); + } + + Console.Write(renderable); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/AnsiConsole.Screen.cs b/src/Spectre.Console/AnsiConsole.Screen.cs index 69e46ba..35740da 100644 --- a/src/Spectre.Console/AnsiConsole.Screen.cs +++ b/src/Spectre.Console/AnsiConsole.Screen.cs @@ -1,19 +1,18 @@ using System; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// A console capable of writing ANSI escape sequences. +/// +public static partial class AnsiConsole { /// - /// A console capable of writing ANSI escape sequences. + /// Switches to an alternate screen buffer if the terminal supports it. /// - public static partial class AnsiConsole + /// The action to execute within the alternate screen buffer. + public static void AlternateScreen(Action action) { - /// - /// Switches to an alternate screen buffer if the terminal supports it. - /// - /// The action to execute within the alternate screen buffer. - public static void AlternateScreen(Action action) - { - Console.AlternateScreen(action); - } + Console.AlternateScreen(action); } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/AnsiConsole.State.cs b/src/Spectre.Console/AnsiConsole.State.cs index 1dc70bd..ca6e209 100644 --- a/src/Spectre.Console/AnsiConsole.State.cs +++ b/src/Spectre.Console/AnsiConsole.State.cs @@ -1,63 +1,62 @@ -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// A console capable of writing ANSI escape sequences. +/// +public static partial class AnsiConsole { + internal static Style CurrentStyle { get; private set; } = Style.Plain; + internal static bool Created { get; private set; } + /// - /// A console capable of writing ANSI escape sequences. + /// Gets or sets the foreground color. /// - public static partial class AnsiConsole + public static Color Foreground { - internal static Style CurrentStyle { get; private set; } = Style.Plain; - internal static bool Created { get; private set; } - - /// - /// Gets or sets the foreground color. - /// - public static Color Foreground - { - get => CurrentStyle.Foreground; - set => CurrentStyle = CurrentStyle.Foreground(value); - } - - /// - /// Gets or sets the background color. - /// - public static Color Background - { - get => CurrentStyle.Background; - set => CurrentStyle = CurrentStyle.Background(value); - } - - /// - /// Gets or sets the text decoration. - /// - public static Decoration Decoration - { - get => CurrentStyle.Decoration; - set => CurrentStyle = CurrentStyle.Decoration(value); - } - - /// - /// Resets colors and text decorations. - /// - public static void Reset() - { - ResetColors(); - ResetDecoration(); - } - - /// - /// Resets the current applied text decorations. - /// - public static void ResetDecoration() - { - Decoration = Decoration.None; - } - - /// - /// Resets the current applied foreground and background colors. - /// - public static void ResetColors() - { - CurrentStyle = Style.Plain; - } + get => CurrentStyle.Foreground; + set => CurrentStyle = CurrentStyle.Foreground(value); } -} + + /// + /// Gets or sets the background color. + /// + public static Color Background + { + get => CurrentStyle.Background; + set => CurrentStyle = CurrentStyle.Background(value); + } + + /// + /// Gets or sets the text decoration. + /// + public static Decoration Decoration + { + get => CurrentStyle.Decoration; + set => CurrentStyle = CurrentStyle.Decoration(value); + } + + /// + /// Resets colors and text decorations. + /// + public static void Reset() + { + ResetColors(); + ResetDecoration(); + } + + /// + /// Resets the current applied text decorations. + /// + public static void ResetDecoration() + { + Decoration = Decoration.None; + } + + /// + /// Resets the current applied foreground and background colors. + /// + public static void ResetColors() + { + CurrentStyle = Style.Plain; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/AnsiConsole.Write.cs b/src/Spectre.Console/AnsiConsole.Write.cs index 62b9083..bb936b1 100644 --- a/src/Spectre.Console/AnsiConsole.Write.cs +++ b/src/Spectre.Console/AnsiConsole.Write.cs @@ -1,253 +1,252 @@ using System; using System.Globalization; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// A console capable of writing ANSI escape sequences. +/// +public static partial class AnsiConsole { /// - /// A console capable of writing ANSI escape sequences. + /// Writes the specified string value to the console. /// - public static partial class AnsiConsole + /// The value to write. + public static void Write(string value) { - /// - /// Writes the specified string value to the console. - /// - /// The value to write. - public static void Write(string value) + Write(value, CurrentStyle); + } + + /// + /// Writes the text representation of the specified 32-bit + /// signed integer value to the console. + /// + /// The value to write. + public static void Write(int value) + { + Write(CultureInfo.CurrentCulture, value); + } + + /// + /// Writes the text representation of the specified 32-bit + /// signed integer value to the console. + /// + /// An object that supplies culture-specific formatting information. + /// The value to write. + public static void Write(IFormatProvider provider, int value) + { + Console.Write(value.ToString(provider), CurrentStyle); + } + + /// + /// Writes the text representation of the specified 32-bit + /// unsigned integer value to the console. + /// + /// The value to write. + public static void Write(uint value) + { + Write(CultureInfo.CurrentCulture, value); + } + + /// + /// Writes the text representation of the specified 32-bit + /// unsigned integer value to the console. + /// + /// An object that supplies culture-specific formatting information. + /// The value to write. + public static void Write(IFormatProvider provider, uint value) + { + Console.Write(value.ToString(provider), CurrentStyle); + } + + /// + /// Writes the text representation of the specified 64-bit + /// signed integer value to the console. + /// + /// The value to write. + public static void Write(long value) + { + Write(CultureInfo.CurrentCulture, value); + } + + /// + /// Writes the text representation of the specified 64-bit + /// signed integer value to the console. + /// + /// An object that supplies culture-specific formatting information. + /// The value to write. + public static void Write(IFormatProvider provider, long value) + { + Console.Write(value.ToString(provider), CurrentStyle); + } + + /// + /// Writes the text representation of the specified 64-bit + /// unsigned integer value to the console. + /// + /// The value to write. + public static void Write(ulong value) + { + Write(CultureInfo.CurrentCulture, value); + } + + /// + /// Writes the text representation of the specified 64-bit + /// unsigned integer value to the console. + /// + /// An object that supplies culture-specific formatting information. + /// The value to write. + public static void Write(IFormatProvider provider, ulong value) + { + Console.Write(value.ToString(provider), CurrentStyle); + } + + /// + /// Writes the text representation of the specified single-precision + /// floating-point value to the console. + /// + /// The value to write. + public static void Write(float value) + { + Write(CultureInfo.CurrentCulture, value); + } + + /// + /// Writes the text representation of the specified single-precision + /// floating-point value to the console. + /// + /// An object that supplies culture-specific formatting information. + /// The value to write. + public static void Write(IFormatProvider provider, float value) + { + Console.Write(value.ToString(provider), CurrentStyle); + } + + /// + /// Writes the text representation of the specified double-precision + /// floating-point value to the console. + /// + /// The value to write. + public static void Write(double value) + { + Write(CultureInfo.CurrentCulture, value); + } + + /// + /// Writes the text representation of the specified double-precision + /// floating-point value to the console. + /// + /// An object that supplies culture-specific formatting information. + /// The value to write. + public static void Write(IFormatProvider provider, double value) + { + Console.Write(value.ToString(provider), CurrentStyle); + } + + /// + /// Writes the text representation of the specified decimal value, to the console. + /// + /// The value to write. + public static void Write(decimal value) + { + Write(CultureInfo.CurrentCulture, value); + } + + /// + /// Writes the text representation of the specified decimal value, to the console. + /// + /// An object that supplies culture-specific formatting information. + /// The value to write. + public static void Write(IFormatProvider provider, decimal value) + { + Console.Write(value.ToString(provider), CurrentStyle); + } + + /// + /// Writes the text representation of the specified boolean value to the console. + /// + /// The value to write. + public static void Write(bool value) + { + Write(CultureInfo.CurrentCulture, value); + } + + /// + /// Writes the text representation of the specified boolean value to the console. + /// + /// An object that supplies culture-specific formatting information. + /// The value to write. + public static void Write(IFormatProvider provider, bool value) + { + Console.Write(value.ToString(provider), CurrentStyle); + } + + /// + /// Writes the specified Unicode character to the console. + /// + /// The value to write. + public static void Write(char value) + { + Write(CultureInfo.CurrentCulture, value); + } + + /// + /// Writes the specified Unicode character to the console. + /// + /// An object that supplies culture-specific formatting information. + /// The value to write. + public static void Write(IFormatProvider provider, char value) + { + Console.Write(value.ToString(provider), CurrentStyle); + } + + /// + /// Writes the specified array of Unicode characters to the console. + /// + /// The value to write. + public static void Write(char[] value) + { + Write(CultureInfo.CurrentCulture, value); + } + + /// + /// Writes the specified array of Unicode characters to the console. + /// + /// An object that supplies culture-specific formatting information. + /// The value to write. + public static void Write(IFormatProvider provider, char[] value) + { + if (value is null) { - Write(value, CurrentStyle); + throw new ArgumentNullException(nameof(value)); } - /// - /// Writes the text representation of the specified 32-bit - /// signed integer value to the console. - /// - /// The value to write. - public static void Write(int value) + for (var index = 0; index < value.Length; index++) { - Write(CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the text representation of the specified 32-bit - /// signed integer value to the console. - /// - /// An object that supplies culture-specific formatting information. - /// The value to write. - public static void Write(IFormatProvider provider, int value) - { - Console.Write(value.ToString(provider), CurrentStyle); - } - - /// - /// Writes the text representation of the specified 32-bit - /// unsigned integer value to the console. - /// - /// The value to write. - public static void Write(uint value) - { - Write(CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the text representation of the specified 32-bit - /// unsigned integer value to the console. - /// - /// An object that supplies culture-specific formatting information. - /// The value to write. - public static void Write(IFormatProvider provider, uint value) - { - Console.Write(value.ToString(provider), CurrentStyle); - } - - /// - /// Writes the text representation of the specified 64-bit - /// signed integer value to the console. - /// - /// The value to write. - public static void Write(long value) - { - Write(CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the text representation of the specified 64-bit - /// signed integer value to the console. - /// - /// An object that supplies culture-specific formatting information. - /// The value to write. - public static void Write(IFormatProvider provider, long value) - { - Console.Write(value.ToString(provider), CurrentStyle); - } - - /// - /// Writes the text representation of the specified 64-bit - /// unsigned integer value to the console. - /// - /// The value to write. - public static void Write(ulong value) - { - Write(CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the text representation of the specified 64-bit - /// unsigned integer value to the console. - /// - /// An object that supplies culture-specific formatting information. - /// The value to write. - public static void Write(IFormatProvider provider, ulong value) - { - Console.Write(value.ToString(provider), CurrentStyle); - } - - /// - /// Writes the text representation of the specified single-precision - /// floating-point value to the console. - /// - /// The value to write. - public static void Write(float value) - { - Write(CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the text representation of the specified single-precision - /// floating-point value to the console. - /// - /// An object that supplies culture-specific formatting information. - /// The value to write. - public static void Write(IFormatProvider provider, float value) - { - Console.Write(value.ToString(provider), CurrentStyle); - } - - /// - /// Writes the text representation of the specified double-precision - /// floating-point value to the console. - /// - /// The value to write. - public static void Write(double value) - { - Write(CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the text representation of the specified double-precision - /// floating-point value to the console. - /// - /// An object that supplies culture-specific formatting information. - /// The value to write. - public static void Write(IFormatProvider provider, double value) - { - Console.Write(value.ToString(provider), CurrentStyle); - } - - /// - /// Writes the text representation of the specified decimal value, to the console. - /// - /// The value to write. - public static void Write(decimal value) - { - Write(CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the text representation of the specified decimal value, to the console. - /// - /// An object that supplies culture-specific formatting information. - /// The value to write. - public static void Write(IFormatProvider provider, decimal value) - { - Console.Write(value.ToString(provider), CurrentStyle); - } - - /// - /// Writes the text representation of the specified boolean value to the console. - /// - /// The value to write. - public static void Write(bool value) - { - Write(CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the text representation of the specified boolean value to the console. - /// - /// An object that supplies culture-specific formatting information. - /// The value to write. - public static void Write(IFormatProvider provider, bool value) - { - Console.Write(value.ToString(provider), CurrentStyle); - } - - /// - /// Writes the specified Unicode character to the console. - /// - /// The value to write. - public static void Write(char value) - { - Write(CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the specified Unicode character to the console. - /// - /// An object that supplies culture-specific formatting information. - /// The value to write. - public static void Write(IFormatProvider provider, char value) - { - Console.Write(value.ToString(provider), CurrentStyle); - } - - /// - /// Writes the specified array of Unicode characters to the console. - /// - /// The value to write. - public static void Write(char[] value) - { - Write(CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the specified array of Unicode characters to the console. - /// - /// An object that supplies culture-specific formatting information. - /// The value to write. - public static void Write(IFormatProvider provider, char[] value) - { - if (value is null) - { - throw new ArgumentNullException(nameof(value)); - } - - for (var index = 0; index < value.Length; index++) - { - Console.Write(value[index].ToString(provider), CurrentStyle); - } - } - - /// - /// Writes the text representation of the specified array of objects, - /// to the console using the specified format information. - /// - /// A composite format string. - /// An array of objects to write. - public static void Write(string format, params object[] args) - { - Write(CultureInfo.CurrentCulture, format, args); - } - - /// - /// Writes the text representation of the specified array of objects, - /// to the console using the specified format information. - /// - /// An object that supplies culture-specific formatting information. - /// A composite format string. - /// An array of objects to write. - public static void Write(IFormatProvider provider, string format, params object[] args) - { - Console.Write(string.Format(provider, format, args), CurrentStyle); + Console.Write(value[index].ToString(provider), CurrentStyle); } } -} + + /// + /// Writes the text representation of the specified array of objects, + /// to the console using the specified format information. + /// + /// A composite format string. + /// An array of objects to write. + public static void Write(string format, params object[] args) + { + Write(CultureInfo.CurrentCulture, format, args); + } + + /// + /// Writes the text representation of the specified array of objects, + /// to the console using the specified format information. + /// + /// An object that supplies culture-specific formatting information. + /// A composite format string. + /// An array of objects to write. + public static void Write(IFormatProvider provider, string format, params object[] args) + { + Console.Write(string.Format(provider, format, args), CurrentStyle); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/AnsiConsole.WriteLine.cs b/src/Spectre.Console/AnsiConsole.WriteLine.cs index 90075b5..afd2687 100644 --- a/src/Spectre.Console/AnsiConsole.WriteLine.cs +++ b/src/Spectre.Console/AnsiConsole.WriteLine.cs @@ -1,273 +1,272 @@ using System; using System.Globalization; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// A console capable of writing ANSI escape sequences. +/// +public static partial class AnsiConsole { /// - /// A console capable of writing ANSI escape sequences. + /// Writes an empty line to the console. /// - public static partial class AnsiConsole + public static void WriteLine() { - /// - /// Writes an empty line to the console. - /// - public static void WriteLine() - { - Console.WriteLine(); - } - - /// - /// Writes the specified string value, followed by the current line terminator, to the console. - /// - /// The value to write. - public static void WriteLine(string value) - { - Console.WriteLine(value, CurrentStyle); - } - - /// - /// Writes the text representation of the specified 32-bit signed integer value, - /// followed by the current line terminator, to the console. - /// - /// The value to write. - public static void WriteLine(int value) - { - WriteLine(CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the text representation of the specified 32-bit signed integer value, - /// followed by the current line terminator, to the console. - /// - /// An object that supplies culture-specific formatting information. - /// The value to write. - public static void WriteLine(IFormatProvider provider, int value) - { - Console.WriteLine(value.ToString(provider), CurrentStyle); - } - - /// - /// Writes the text representation of the specified 32-bit unsigned integer value, - /// followed by the current line terminator, to the console. - /// - /// The value to write. - public static void WriteLine(uint value) - { - WriteLine(CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the text representation of the specified 32-bit unsigned integer value, - /// followed by the current line terminator, to the console. - /// - /// An object that supplies culture-specific formatting information. - /// The value to write. - public static void WriteLine(IFormatProvider provider, uint value) - { - Console.WriteLine(value.ToString(provider), CurrentStyle); - } - - /// - /// Writes the text representation of the specified 64-bit signed integer value, - /// followed by the current line terminator, to the console. - /// - /// The value to write. - public static void WriteLine(long value) - { - WriteLine(CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the text representation of the specified 64-bit signed integer value, - /// followed by the current line terminator, to the console. - /// - /// An object that supplies culture-specific formatting information. - /// The value to write. - public static void WriteLine(IFormatProvider provider, long value) - { - Console.WriteLine(value.ToString(provider), CurrentStyle); - } - - /// - /// Writes the text representation of the specified 64-bit unsigned integer value, - /// followed by the current line terminator, to the console. - /// - /// The value to write. - public static void WriteLine(ulong value) - { - WriteLine(CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the text representation of the specified 64-bit unsigned integer value, - /// followed by the current line terminator, to the console. - /// - /// An object that supplies culture-specific formatting information. - /// The value to write. - public static void WriteLine(IFormatProvider provider, ulong value) - { - Console.WriteLine(value.ToString(provider), CurrentStyle); - } - - /// - /// Writes the text representation of the specified single-precision floating-point - /// value, followed by the current line terminator, to the console. - /// - /// The value to write. - public static void WriteLine(float value) - { - WriteLine(CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the text representation of the specified single-precision floating-point - /// value, followed by the current line terminator, to the console. - /// - /// An object that supplies culture-specific formatting information. - /// The value to write. - public static void WriteLine(IFormatProvider provider, float value) - { - Console.WriteLine(value.ToString(provider), CurrentStyle); - } - - /// - /// Writes the text representation of the specified double-precision floating-point - /// value, followed by the current line terminator, to the console. - /// - /// The value to write. - public static void WriteLine(double value) - { - WriteLine(CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the text representation of the specified double-precision floating-point - /// value, followed by the current line terminator, to the console. - /// - /// An object that supplies culture-specific formatting information. - /// The value to write. - public static void WriteLine(IFormatProvider provider, double value) - { - Console.WriteLine(value.ToString(provider), CurrentStyle); - } - - /// - /// Writes the text representation of the specified decimal value, - /// followed by the current line terminator, to the console. - /// - /// The value to write. - public static void WriteLine(decimal value) - { - WriteLine(CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the text representation of the specified decimal value, - /// followed by the current line terminator, to the console. - /// - /// An object that supplies culture-specific formatting information. - /// The value to write. - public static void WriteLine(IFormatProvider provider, decimal value) - { - Console.WriteLine(value.ToString(provider), CurrentStyle); - } - - /// - /// Writes the text representation of the specified boolean value, - /// followed by the current line terminator, to the console. - /// - /// The value to write. - public static void WriteLine(bool value) - { - WriteLine(CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the text representation of the specified boolean value, - /// followed by the current line terminator, to the console. - /// - /// An object that supplies culture-specific formatting information. - /// The value to write. - public static void WriteLine(IFormatProvider provider, bool value) - { - Console.WriteLine(value.ToString(provider), CurrentStyle); - } - - /// - /// Writes the specified Unicode character, followed by the current - /// line terminator, value to the console. - /// - /// The value to write. - public static void WriteLine(char value) - { - WriteLine(CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the specified Unicode character, followed by the current - /// line terminator, value to the console. - /// - /// An object that supplies culture-specific formatting information. - /// The value to write. - public static void WriteLine(IFormatProvider provider, char value) - { - Console.WriteLine(value.ToString(provider), CurrentStyle); - } - - /// - /// Writes the specified array of Unicode characters, followed by the current - /// line terminator, value to the console. - /// - /// The value to write. - public static void WriteLine(char[] value) - { - WriteLine(CultureInfo.CurrentCulture, value); - } - - /// - /// Writes the specified array of Unicode characters, followed by the current - /// line terminator, value to the console. - /// - /// An object that supplies culture-specific formatting information. - /// The value to write. - public static void WriteLine(IFormatProvider provider, char[] value) - { - if (value is null) - { - throw new ArgumentNullException(nameof(value)); - } - - for (var index = 0; index < value.Length; index++) - { - Console.Write(value[index].ToString(provider), CurrentStyle); - } - - Console.WriteLine(); - } - - /// - /// Writes the text representation of the specified array of objects, - /// followed by the current line terminator, to the console - /// using the specified format information. - /// - /// A composite format string. - /// An array of objects to write. - public static void WriteLine(string format, params object[] args) - { - WriteLine(CultureInfo.CurrentCulture, format, args); - } - - /// - /// Writes the text representation of the specified array of objects, - /// followed by the current line terminator, to the console - /// using the specified format information. - /// - /// An object that supplies culture-specific formatting information. - /// A composite format string. - /// An array of objects to write. - public static void WriteLine(IFormatProvider provider, string format, params object[] args) - { - Console.WriteLine(string.Format(provider, format, args), CurrentStyle); - } + Console.WriteLine(); } -} + + /// + /// Writes the specified string value, followed by the current line terminator, to the console. + /// + /// The value to write. + public static void WriteLine(string value) + { + Console.WriteLine(value, CurrentStyle); + } + + /// + /// Writes the text representation of the specified 32-bit signed integer value, + /// followed by the current line terminator, to the console. + /// + /// The value to write. + public static void WriteLine(int value) + { + WriteLine(CultureInfo.CurrentCulture, value); + } + + /// + /// Writes the text representation of the specified 32-bit signed integer value, + /// followed by the current line terminator, to the console. + /// + /// An object that supplies culture-specific formatting information. + /// The value to write. + public static void WriteLine(IFormatProvider provider, int value) + { + Console.WriteLine(value.ToString(provider), CurrentStyle); + } + + /// + /// Writes the text representation of the specified 32-bit unsigned integer value, + /// followed by the current line terminator, to the console. + /// + /// The value to write. + public static void WriteLine(uint value) + { + WriteLine(CultureInfo.CurrentCulture, value); + } + + /// + /// Writes the text representation of the specified 32-bit unsigned integer value, + /// followed by the current line terminator, to the console. + /// + /// An object that supplies culture-specific formatting information. + /// The value to write. + public static void WriteLine(IFormatProvider provider, uint value) + { + Console.WriteLine(value.ToString(provider), CurrentStyle); + } + + /// + /// Writes the text representation of the specified 64-bit signed integer value, + /// followed by the current line terminator, to the console. + /// + /// The value to write. + public static void WriteLine(long value) + { + WriteLine(CultureInfo.CurrentCulture, value); + } + + /// + /// Writes the text representation of the specified 64-bit signed integer value, + /// followed by the current line terminator, to the console. + /// + /// An object that supplies culture-specific formatting information. + /// The value to write. + public static void WriteLine(IFormatProvider provider, long value) + { + Console.WriteLine(value.ToString(provider), CurrentStyle); + } + + /// + /// Writes the text representation of the specified 64-bit unsigned integer value, + /// followed by the current line terminator, to the console. + /// + /// The value to write. + public static void WriteLine(ulong value) + { + WriteLine(CultureInfo.CurrentCulture, value); + } + + /// + /// Writes the text representation of the specified 64-bit unsigned integer value, + /// followed by the current line terminator, to the console. + /// + /// An object that supplies culture-specific formatting information. + /// The value to write. + public static void WriteLine(IFormatProvider provider, ulong value) + { + Console.WriteLine(value.ToString(provider), CurrentStyle); + } + + /// + /// Writes the text representation of the specified single-precision floating-point + /// value, followed by the current line terminator, to the console. + /// + /// The value to write. + public static void WriteLine(float value) + { + WriteLine(CultureInfo.CurrentCulture, value); + } + + /// + /// Writes the text representation of the specified single-precision floating-point + /// value, followed by the current line terminator, to the console. + /// + /// An object that supplies culture-specific formatting information. + /// The value to write. + public static void WriteLine(IFormatProvider provider, float value) + { + Console.WriteLine(value.ToString(provider), CurrentStyle); + } + + /// + /// Writes the text representation of the specified double-precision floating-point + /// value, followed by the current line terminator, to the console. + /// + /// The value to write. + public static void WriteLine(double value) + { + WriteLine(CultureInfo.CurrentCulture, value); + } + + /// + /// Writes the text representation of the specified double-precision floating-point + /// value, followed by the current line terminator, to the console. + /// + /// An object that supplies culture-specific formatting information. + /// The value to write. + public static void WriteLine(IFormatProvider provider, double value) + { + Console.WriteLine(value.ToString(provider), CurrentStyle); + } + + /// + /// Writes the text representation of the specified decimal value, + /// followed by the current line terminator, to the console. + /// + /// The value to write. + public static void WriteLine(decimal value) + { + WriteLine(CultureInfo.CurrentCulture, value); + } + + /// + /// Writes the text representation of the specified decimal value, + /// followed by the current line terminator, to the console. + /// + /// An object that supplies culture-specific formatting information. + /// The value to write. + public static void WriteLine(IFormatProvider provider, decimal value) + { + Console.WriteLine(value.ToString(provider), CurrentStyle); + } + + /// + /// Writes the text representation of the specified boolean value, + /// followed by the current line terminator, to the console. + /// + /// The value to write. + public static void WriteLine(bool value) + { + WriteLine(CultureInfo.CurrentCulture, value); + } + + /// + /// Writes the text representation of the specified boolean value, + /// followed by the current line terminator, to the console. + /// + /// An object that supplies culture-specific formatting information. + /// The value to write. + public static void WriteLine(IFormatProvider provider, bool value) + { + Console.WriteLine(value.ToString(provider), CurrentStyle); + } + + /// + /// Writes the specified Unicode character, followed by the current + /// line terminator, value to the console. + /// + /// The value to write. + public static void WriteLine(char value) + { + WriteLine(CultureInfo.CurrentCulture, value); + } + + /// + /// Writes the specified Unicode character, followed by the current + /// line terminator, value to the console. + /// + /// An object that supplies culture-specific formatting information. + /// The value to write. + public static void WriteLine(IFormatProvider provider, char value) + { + Console.WriteLine(value.ToString(provider), CurrentStyle); + } + + /// + /// Writes the specified array of Unicode characters, followed by the current + /// line terminator, value to the console. + /// + /// The value to write. + public static void WriteLine(char[] value) + { + WriteLine(CultureInfo.CurrentCulture, value); + } + + /// + /// Writes the specified array of Unicode characters, followed by the current + /// line terminator, value to the console. + /// + /// An object that supplies culture-specific formatting information. + /// The value to write. + public static void WriteLine(IFormatProvider provider, char[] value) + { + if (value is null) + { + throw new ArgumentNullException(nameof(value)); + } + + for (var index = 0; index < value.Length; index++) + { + Console.Write(value[index].ToString(provider), CurrentStyle); + } + + Console.WriteLine(); + } + + /// + /// Writes the text representation of the specified array of objects, + /// followed by the current line terminator, to the console + /// using the specified format information. + /// + /// A composite format string. + /// An array of objects to write. + public static void WriteLine(string format, params object[] args) + { + WriteLine(CultureInfo.CurrentCulture, format, args); + } + + /// + /// Writes the text representation of the specified array of objects, + /// followed by the current line terminator, to the console + /// using the specified format information. + /// + /// An object that supplies culture-specific formatting information. + /// A composite format string. + /// An array of objects to write. + public static void WriteLine(IFormatProvider provider, string format, params object[] args) + { + Console.WriteLine(string.Format(provider, format, args), CurrentStyle); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/AnsiConsole.cs b/src/Spectre.Console/AnsiConsole.cs index 85cf2c7..ac88d3c 100644 --- a/src/Spectre.Console/AnsiConsole.cs +++ b/src/Spectre.Console/AnsiConsole.cs @@ -1,78 +1,77 @@ using System; -namespace Spectre.Console -{ - /// - /// A console capable of writing ANSI escape sequences. - /// - public static partial class AnsiConsole - { - private static Recorder? _recorder; - private static Lazy _console = new Lazy( - () => - { - var console = Create(new AnsiConsoleSettings - { - Ansi = AnsiSupport.Detect, - ColorSystem = ColorSystemSupport.Detect, - Out = new AnsiConsoleOutput(System.Console.Out), - }); +namespace Spectre.Console; - Created = true; - return console; +/// +/// A console capable of writing ANSI escape sequences. +/// +public static partial class AnsiConsole +{ + private static Recorder? _recorder; + private static Lazy _console = new Lazy( + () => + { + var console = Create(new AnsiConsoleSettings + { + Ansi = AnsiSupport.Detect, + ColorSystem = ColorSystemSupport.Detect, + Out = new AnsiConsoleOutput(System.Console.Out), }); - /// - /// Gets or sets the underlying . - /// - public static IAnsiConsole Console + Created = true; + return console; + }); + + /// + /// Gets or sets the underlying . + /// + public static IAnsiConsole Console + { + get { - get - { - return _recorder ?? _console.Value; - } - set - { - _console = new Lazy(() => value); - - if (_recorder != null) - { - // Recreate the recorder - _recorder = _recorder.Clone(value); - } - - Created = true; - } + return _recorder ?? _console.Value; } - - /// - /// Gets the . - /// - public static IAnsiConsoleCursor Cursor => _recorder?.Cursor ?? _console.Value.Cursor; - - /// - /// Gets the console profile. - /// - public static Profile Profile => Console.Profile; - - /// - /// Creates a new instance - /// from the provided settings. - /// - /// The settings to use. - /// An instance. - public static IAnsiConsole Create(AnsiConsoleSettings settings) + set { - var factory = new AnsiConsoleFactory(); - return factory.Create(settings); - } + _console = new Lazy(() => value); - /// - /// Clears the console. - /// - public static void Clear() - { - Console.Clear(); + if (_recorder != null) + { + // Recreate the recorder + _recorder = _recorder.Clone(value); + } + + Created = true; } } -} + + /// + /// Gets the . + /// + public static IAnsiConsoleCursor Cursor => _recorder?.Cursor ?? _console.Value.Cursor; + + /// + /// Gets the console profile. + /// + public static Profile Profile => Console.Profile; + + /// + /// Creates a new instance + /// from the provided settings. + /// + /// The settings to use. + /// An instance. + public static IAnsiConsole Create(AnsiConsoleSettings settings) + { + var factory = new AnsiConsoleFactory(); + return factory.Create(settings); + } + + /// + /// Clears the console. + /// + public static void Clear() + { + Console.Clear(); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/AnsiConsoleFactory.cs b/src/Spectre.Console/AnsiConsoleFactory.cs index 178ea9d..6f0dbba 100644 --- a/src/Spectre.Console/AnsiConsoleFactory.cs +++ b/src/Spectre.Console/AnsiConsoleFactory.cs @@ -3,110 +3,109 @@ using System.Runtime.InteropServices; using Spectre.Console.Enrichment; using Spectre.Console.Internal; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Factory for creating an ANSI console. +/// +public sealed class AnsiConsoleFactory { /// - /// Factory for creating an ANSI console. + /// Creates an ANSI console. /// - public sealed class AnsiConsoleFactory + /// The settings. + /// An implementation of . + public IAnsiConsole Create(AnsiConsoleSettings settings) { - /// - /// Creates an ANSI console. - /// - /// The settings. - /// An implementation of . - public IAnsiConsole Create(AnsiConsoleSettings settings) + if (settings is null) { - if (settings is null) - { - throw new ArgumentNullException(nameof(settings)); - } - - 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, output.Writer); - - // Use console encoding or fall back to provided 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 - ? ColorSystemDetector.Detect(supportsAnsi) - : (ColorSystem)settings.ColorSystem; - - // Get whether or not we consider the terminal interactive - var interactive = settings.Interactive == InteractionSupport.Yes; - if (settings.Interactive == InteractionSupport.Detect) - { - interactive = Environment.UserInteractive; - } - - var profile = new Profile(output, encoding); - - profile.Capabilities.ColorSystem = colorSystem; - profile.Capabilities.Ansi = supportsAnsi; - profile.Capabilities.Links = supportsAnsi && !legacyConsole; - profile.Capabilities.Legacy = legacyConsole; - profile.Capabilities.Interactive = interactive; - profile.Capabilities.Unicode = encoding.EncodingName.ContainsExact("Unicode"); - profile.Capabilities.AlternateBuffer = supportsAnsi && !legacyConsole; - - // Enrich the profile - ProfileEnricher.Enrich( - profile, - settings.Enrichment, - settings.EnvironmentVariables); - - return new AnsiConsoleFacade( - profile, - settings.ExclusivityMode ?? new DefaultExclusivityMode()); + throw new ArgumentNullException(nameof(settings)); } - private static (bool Ansi, bool Legacy) DetectAnsi(AnsiConsoleSettings settings, System.IO.TextWriter buffer) + var output = settings.Out ?? new AnsiConsoleOutput(System.Console.Out); + if (output.Writer == null) { - var supportsAnsi = settings.Ansi == AnsiSupport.Yes; - var legacyConsole = false; + throw new InvalidOperationException("Output writer was null"); + } - if (settings.Ansi == AnsiSupport.Detect) + // Detect if the terminal support ANSI or not + var (supportsAnsi, legacyConsole) = DetectAnsi(settings, output.Writer); + + // Use console encoding or fall back to provided 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 + ? ColorSystemDetector.Detect(supportsAnsi) + : (ColorSystem)settings.ColorSystem; + + // Get whether or not we consider the terminal interactive + var interactive = settings.Interactive == InteractionSupport.Yes; + if (settings.Interactive == InteractionSupport.Detect) + { + interactive = Environment.UserInteractive; + } + + var profile = new Profile(output, encoding); + + profile.Capabilities.ColorSystem = colorSystem; + profile.Capabilities.Ansi = supportsAnsi; + profile.Capabilities.Links = supportsAnsi && !legacyConsole; + profile.Capabilities.Legacy = legacyConsole; + profile.Capabilities.Interactive = interactive; + profile.Capabilities.Unicode = encoding.EncodingName.ContainsExact("Unicode"); + profile.Capabilities.AlternateBuffer = supportsAnsi && !legacyConsole; + + // Enrich the profile + ProfileEnricher.Enrich( + profile, + settings.Enrichment, + settings.EnvironmentVariables); + + return new AnsiConsoleFacade( + profile, + settings.ExclusivityMode ?? new DefaultExclusivityMode()); + } + + private static (bool Ansi, bool Legacy) DetectAnsi(AnsiConsoleSettings settings, System.IO.TextWriter buffer) + { + var supportsAnsi = settings.Ansi == AnsiSupport.Yes; + var legacyConsole = false; + + if (settings.Ansi == AnsiSupport.Detect) + { + (supportsAnsi, legacyConsole) = AnsiDetector.Detect(buffer.IsStandardError(), true); + + // Check whether or not this is a legacy console from the existing instance (if any). + // We need to do this because once we upgrade the console to support ENABLE_VIRTUAL_TERMINAL_PROCESSING + // on Windows, there is no way of detecting whether or not we're running on a legacy console or not. + if (AnsiConsole.Created && !legacyConsole && (buffer.IsStandardOut() || buffer.IsStandardError()) && AnsiConsole.Profile.Capabilities.Legacy) { - (supportsAnsi, legacyConsole) = AnsiDetector.Detect(buffer.IsStandardError(), true); - - // Check whether or not this is a legacy console from the existing instance (if any). - // We need to do this because once we upgrade the console to support ENABLE_VIRTUAL_TERMINAL_PROCESSING - // on Windows, there is no way of detecting whether or not we're running on a legacy console or not. - if (AnsiConsole.Created && !legacyConsole && (buffer.IsStandardOut() || buffer.IsStandardError()) && AnsiConsole.Profile.Capabilities.Legacy) - { - legacyConsole = AnsiConsole.Profile.Capabilities.Legacy; - } + legacyConsole = AnsiConsole.Profile.Capabilities.Legacy; } - else + } + else + { + if (buffer.IsStandardOut() || buffer.IsStandardError()) { - if (buffer.IsStandardOut() || buffer.IsStandardError()) + // Are we running on Windows? + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - // Are we running on Windows? - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + // Not the first console we're creating? + if (AnsiConsole.Created) { - // Not the first console we're creating? - if (AnsiConsole.Created) - { - legacyConsole = AnsiConsole.Profile.Capabilities.Legacy; - } - else - { - // Try detecting whether or not this is a legacy console - (_, legacyConsole) = AnsiDetector.Detect(buffer.IsStandardError(), false); - } + legacyConsole = AnsiConsole.Profile.Capabilities.Legacy; + } + else + { + // Try detecting whether or not this is a legacy console + (_, legacyConsole) = AnsiDetector.Detect(buffer.IsStandardError(), false); } } } - - return (supportsAnsi, legacyConsole); } + + return (supportsAnsi, legacyConsole); } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/AnsiConsoleOutput.cs b/src/Spectre.Console/AnsiConsoleOutput.cs index 907def7..392eaef 100644 --- a/src/Spectre.Console/AnsiConsoleOutput.cs +++ b/src/Spectre.Console/AnsiConsoleOutput.cs @@ -2,57 +2,56 @@ using System; using System.IO; using System.Text; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Represents console output. +/// +public sealed class AnsiConsoleOutput : IAnsiConsoleOutput { - /// - /// Represents console output. - /// - public sealed class AnsiConsoleOutput : IAnsiConsoleOutput + /// + public TextWriter Writer { get; } + + /// + public bool IsTerminal { - /// - public TextWriter Writer { get; } - - /// - public bool IsTerminal + get { - get + if (Writer.IsStandardOut()) { - if (Writer.IsStandardOut()) - { - return !System.Console.IsOutputRedirected; - } - - if (Writer.IsStandardError()) - { - return !System.Console.IsErrorRedirected; - } - - return false; + return !System.Console.IsOutputRedirected; } - } - /// - 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()) + if (Writer.IsStandardError()) { - System.Console.OutputEncoding = encoding; + 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; + } + } +} \ No newline at end of file diff --git a/src/Spectre.Console/AnsiConsoleSettings.cs b/src/Spectre.Console/AnsiConsoleSettings.cs index 7038eb2..6fdea92 100644 --- a/src/Spectre.Console/AnsiConsoleSettings.cs +++ b/src/Spectre.Console/AnsiConsoleSettings.cs @@ -1,56 +1,55 @@ using System.Collections.Generic; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Settings used when building a . +/// +public sealed class AnsiConsoleSettings { /// - /// Settings used when building a . + /// Gets or sets a value indicating whether or + /// not ANSI escape sequences are supported. /// - public sealed class AnsiConsoleSettings + public AnsiSupport Ansi { get; set; } + + /// + /// Gets or sets the color system to use. + /// + public ColorSystemSupport ColorSystem { get; set; } = ColorSystemSupport.Detect; + + /// + /// Gets or sets the out buffer. + /// + public IAnsiConsoleOutput? Out { get; set; } + + /// + /// Gets or sets a value indicating whether or not the + /// terminal is interactive or not. + /// + public InteractionSupport Interactive { get; set; } + + /// + /// Gets or sets the exclusivity mode. + /// + public IExclusivityMode? ExclusivityMode { get; set; } + + /// + /// Gets or sets the profile enrichments settings. + /// + public ProfileEnrichment Enrichment { get; set; } + + /// + /// Gets or sets the environment variables. + /// If not value is provided the default environment variables will be used. + /// + public Dictionary? EnvironmentVariables { get; set; } + + /// + /// Initializes a new instance of the class. + /// + public AnsiConsoleSettings() { - /// - /// Gets or sets a value indicating whether or - /// not ANSI escape sequences are supported. - /// - public AnsiSupport Ansi { get; set; } - - /// - /// Gets or sets the color system to use. - /// - public ColorSystemSupport ColorSystem { get; set; } = ColorSystemSupport.Detect; - - /// - /// Gets or sets the out buffer. - /// - public IAnsiConsoleOutput? Out { get; set; } - - /// - /// Gets or sets a value indicating whether or not the - /// terminal is interactive or not. - /// - public InteractionSupport Interactive { get; set; } - - /// - /// Gets or sets the exclusivity mode. - /// - public IExclusivityMode? ExclusivityMode { get; set; } - - /// - /// Gets or sets the profile enrichments settings. - /// - public ProfileEnrichment Enrichment { get; set; } - - /// - /// Gets or sets the environment variables. - /// If not value is provided the default environment variables will be used. - /// - public Dictionary? EnvironmentVariables { get; set; } - - /// - /// Initializes a new instance of the class. - /// - public AnsiConsoleSettings() - { - Enrichment = new ProfileEnrichment(); - } + Enrichment = new ProfileEnrichment(); } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/AnsiSupport.cs b/src/Spectre.Console/AnsiSupport.cs index 8a85026..84f80f1 100644 --- a/src/Spectre.Console/AnsiSupport.cs +++ b/src/Spectre.Console/AnsiSupport.cs @@ -1,24 +1,23 @@ -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Determines ANSI escape sequence support. +/// +public enum AnsiSupport { /// - /// Determines ANSI escape sequence support. + /// ANSI escape sequence support should + /// be detected by the system. /// - public enum AnsiSupport - { - /// - /// ANSI escape sequence support should - /// be detected by the system. - /// - Detect = 0, + Detect = 0, - /// - /// ANSI escape sequences are supported. - /// - Yes = 1, + /// + /// ANSI escape sequences are supported. + /// + Yes = 1, - /// - /// ANSI escape sequences are not supported. - /// - No = 2, - } -} + /// + /// ANSI escape sequences are not supported. + /// + No = 2, +} \ No newline at end of file diff --git a/src/Spectre.Console/BoxBorder.Known.cs b/src/Spectre.Console/BoxBorder.Known.cs index 192648c..e7e4730 100644 --- a/src/Spectre.Console/BoxBorder.Known.cs +++ b/src/Spectre.Console/BoxBorder.Known.cs @@ -1,42 +1,41 @@ using System.Diagnostics.CodeAnalysis; using Spectre.Console.Rendering; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Represents a border. +/// +public abstract partial class BoxBorder { /// - /// Represents a border. + /// Gets an invisible border. /// - public abstract partial class BoxBorder - { - /// - /// Gets an invisible border. - /// - public static BoxBorder None { get; } = new NoBoxBorder(); + public static BoxBorder None { get; } = new NoBoxBorder(); - /// - /// Gets an ASCII border. - /// - public static BoxBorder Ascii { get; } = new AsciiBoxBorder(); + /// + /// Gets an ASCII border. + /// + public static BoxBorder Ascii { get; } = new AsciiBoxBorder(); - /// - /// Gets a double border. - /// - [SuppressMessage("Naming", "CA1720:Identifier contains type name")] - public static BoxBorder Double { get; } = new DoubleBoxBorder(); + /// + /// Gets a double border. + /// + [SuppressMessage("Naming", "CA1720:Identifier contains type name")] + public static BoxBorder Double { get; } = new DoubleBoxBorder(); - /// - /// Gets a heavy border. - /// - public static BoxBorder Heavy { get; } = new HeavyBoxBorder(); + /// + /// Gets a heavy border. + /// + public static BoxBorder Heavy { get; } = new HeavyBoxBorder(); - /// - /// Gets a rounded border. - /// - public static BoxBorder Rounded { get; } = new RoundedBoxBorder(); + /// + /// Gets a rounded border. + /// + public static BoxBorder Rounded { get; } = new RoundedBoxBorder(); - /// - /// Gets a square border. - /// - public static BoxBorder Square { get; } = new SquareBoxBorder(); - } -} + /// + /// Gets a square border. + /// + public static BoxBorder Square { get; } = new SquareBoxBorder(); +} \ No newline at end of file diff --git a/src/Spectre.Console/BoxBorder.cs b/src/Spectre.Console/BoxBorder.cs index 52e2ca8..8cd5e87 100644 --- a/src/Spectre.Console/BoxBorder.cs +++ b/src/Spectre.Console/BoxBorder.cs @@ -1,22 +1,21 @@ using Spectre.Console.Rendering; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Represents a border. +/// +public abstract partial class BoxBorder { /// - /// Represents a border. + /// Gets the safe border for this border or null if none exist. /// - public abstract partial class BoxBorder - { - /// - /// Gets the safe border for this border or null if none exist. - /// - public virtual BoxBorder? SafeBorder { get; } + public virtual BoxBorder? SafeBorder { get; } - /// - /// Gets the string representation of the specified border part. - /// - /// The part to get the character representation for. - /// A character representation of the specified border part. - public abstract string GetPart(BoxBorderPart part); - } -} + /// + /// Gets the string representation of the specified border part. + /// + /// The part to get the character representation for. + /// A character representation of the specified border part. + public abstract string GetPart(BoxBorderPart part); +} \ No newline at end of file diff --git a/src/Spectre.Console/Capabilities.cs b/src/Spectre.Console/Capabilities.cs index 3e2a168..9a4ec30 100644 --- a/src/Spectre.Console/Capabilities.cs +++ b/src/Spectre.Console/Capabilities.cs @@ -1,73 +1,72 @@ using System; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Represents console capabilities. +/// +public sealed class Capabilities : IReadOnlyCapabilities { + private readonly IAnsiConsoleOutput _out; + /// - /// Represents console capabilities. + /// Gets or sets the color system. /// - public sealed class Capabilities : IReadOnlyCapabilities + public ColorSystem ColorSystem { get; set; } + + /// + /// Gets or sets a value indicating whether or not + /// the console supports VT/ANSI control codes. + /// + public bool Ansi { get; set; } + + /// + /// Gets or sets a value indicating whether or not + /// the console support links. + /// + public bool Links { get; set; } + + /// + /// Gets or sets a value indicating whether or not + /// this is a legacy console (cmd.exe) on an OS + /// prior to Windows 10. + /// + /// + /// Only relevant when running on Microsoft Windows. + /// + public bool Legacy { get; set; } + + /// + /// Gets a value indicating whether or not + /// the output is a terminal. + /// + [Obsolete("Use Profile.Out.IsTerminal instead")] + public bool IsTerminal => _out.IsTerminal; + + /// + /// Gets or sets a value indicating whether + /// or not the console supports interaction. + /// + public bool Interactive { get; set; } + + /// + /// Gets or sets a value indicating whether + /// or not the console supports Unicode. + /// + public bool Unicode { get; set; } + + /// + /// Gets or sets a value indicating whether + /// or not the console supports alternate buffers. + /// + public bool AlternateBuffer { get; set; } + + /// + /// Initializes a new instance of the + /// class. + /// + internal Capabilities(IAnsiConsoleOutput @out) { - private readonly IAnsiConsoleOutput _out; - - /// - /// Gets or sets the color system. - /// - public ColorSystem ColorSystem { get; set; } - - /// - /// Gets or sets a value indicating whether or not - /// the console supports VT/ANSI control codes. - /// - public bool Ansi { get; set; } - - /// - /// Gets or sets a value indicating whether or not - /// the console support links. - /// - public bool Links { get; set; } - - /// - /// Gets or sets a value indicating whether or not - /// this is a legacy console (cmd.exe) on an OS - /// prior to Windows 10. - /// - /// - /// Only relevant when running on Microsoft Windows. - /// - public bool Legacy { get; set; } - - /// - /// Gets a value indicating whether or not - /// the output is a terminal. - /// - [Obsolete("Use Profile.Out.IsTerminal instead")] - public bool IsTerminal => _out.IsTerminal; - - /// - /// Gets or sets a value indicating whether - /// or not the console supports interaction. - /// - public bool Interactive { get; set; } - - /// - /// Gets or sets a value indicating whether - /// or not the console supports Unicode. - /// - public bool Unicode { get; set; } - - /// - /// Gets or sets a value indicating whether - /// or not the console supports alternate buffers. - /// - public bool AlternateBuffer { get; set; } - - /// - /// Initializes a new instance of the - /// class. - /// - internal Capabilities(IAnsiConsoleOutput @out) - { - _out = @out ?? throw new ArgumentNullException(nameof(@out)); - } + _out = @out ?? throw new ArgumentNullException(nameof(@out)); } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Annotations/CommandArgumentAttribute.cs b/src/Spectre.Console/Cli/Annotations/CommandArgumentAttribute.cs index 0e0c6a2..44b0a4c 100644 --- a/src/Spectre.Console/Cli/Annotations/CommandArgumentAttribute.cs +++ b/src/Spectre.Console/Cli/Annotations/CommandArgumentAttribute.cs @@ -1,53 +1,52 @@ using System; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// An attribute representing a command argument. +/// +/// +[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] +public sealed class CommandArgumentAttribute : Attribute { /// - /// An attribute representing a command argument. + /// Gets the argument position. /// - /// - [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] - public sealed class CommandArgumentAttribute : Attribute + /// The argument position. + public int Position { get; } + + /// + /// Gets the value name of the argument. + /// + /// The value name of the argument. + public string ValueName { get; } + + /// + /// Gets a value indicating whether the argument is required. + /// + /// + /// true if the argument is required; otherwise, false. + /// + public bool IsRequired { get; } + + /// + /// Initializes a new instance of the class. + /// + /// The argument position. + /// The argument template. + public CommandArgumentAttribute(int position, string template) { - /// - /// Gets the argument position. - /// - /// The argument position. - public int Position { get; } - - /// - /// Gets the value name of the argument. - /// - /// The value name of the argument. - public string ValueName { get; } - - /// - /// Gets a value indicating whether the argument is required. - /// - /// - /// true if the argument is required; otherwise, false. - /// - public bool IsRequired { get; } - - /// - /// Initializes a new instance of the class. - /// - /// The argument position. - /// The argument template. - public CommandArgumentAttribute(int position, string template) + if (template == null) { - if (template == null) - { - throw new ArgumentNullException(nameof(template)); - } - - // Parse the option template. - var result = TemplateParser.ParseArgumentTemplate(template); - - // Assign the result. - Position = position; - ValueName = result.Value; - IsRequired = result.Required; + throw new ArgumentNullException(nameof(template)); } + + // Parse the option template. + var result = TemplateParser.ParseArgumentTemplate(template); + + // Assign the result. + Position = position; + ValueName = result.Value; + IsRequired = result.Required; } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Annotations/CommandOptionAttribute.cs b/src/Spectre.Console/Cli/Annotations/CommandOptionAttribute.cs index e13c9aa..f57068d 100644 --- a/src/Spectre.Console/Cli/Annotations/CommandOptionAttribute.cs +++ b/src/Spectre.Console/Cli/Annotations/CommandOptionAttribute.cs @@ -2,69 +2,68 @@ using System; using System.Collections.Generic; using System.Linq; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// An attribute representing a command option. +/// +/// +[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] +public sealed class CommandOptionAttribute : Attribute { /// - /// An attribute representing a command option. + /// Gets the long names of the option. /// - /// - [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] - public sealed class CommandOptionAttribute : Attribute + /// The option's long names. + public IReadOnlyList LongNames { get; } + + /// + /// Gets the short names of the option. + /// + /// The option's short names. + public IReadOnlyList ShortNames { get; } + + /// + /// Gets the value name of the option. + /// + /// The option's value name. + public string? ValueName { get; } + + /// + /// Gets a value indicating whether the value is optional. + /// + public bool ValueIsOptional { get; } + + /// + /// Gets or sets a value indicating whether this option is hidden from the help text. + /// + public bool IsHidden { get; set; } + + /// + /// Initializes a new instance of the class. + /// + /// The option template. + public CommandOptionAttribute(string template) { - /// - /// Gets the long names of the option. - /// - /// The option's long names. - public IReadOnlyList LongNames { get; } - - /// - /// Gets the short names of the option. - /// - /// The option's short names. - public IReadOnlyList ShortNames { get; } - - /// - /// Gets the value name of the option. - /// - /// The option's value name. - public string? ValueName { get; } - - /// - /// Gets a value indicating whether the value is optional. - /// - public bool ValueIsOptional { get; } - - /// - /// Gets or sets a value indicating whether this option is hidden from the help text. - /// - public bool IsHidden { get; set; } - - /// - /// Initializes a new instance of the class. - /// - /// The option template. - public CommandOptionAttribute(string template) + if (template == null) { - if (template == null) - { - throw new ArgumentNullException(nameof(template)); - } - - // Parse the option template. - var result = TemplateParser.ParseOptionTemplate(template); - - // Assign the result. - LongNames = result.LongNames; - ShortNames = result.ShortNames; - ValueName = result.Value; - ValueIsOptional = result.ValueIsOptional; + throw new ArgumentNullException(nameof(template)); } - internal bool IsMatch(string name) - { - return - ShortNames.Contains(name, StringComparer.Ordinal) || - LongNames.Contains(name, StringComparer.Ordinal); - } + // Parse the option template. + var result = TemplateParser.ParseOptionTemplate(template); + + // Assign the result. + LongNames = result.LongNames; + ShortNames = result.ShortNames; + ValueName = result.Value; + ValueIsOptional = result.ValueIsOptional; } -} + + internal bool IsMatch(string name) + { + return + ShortNames.Contains(name, StringComparer.Ordinal) || + LongNames.Contains(name, StringComparer.Ordinal); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Annotations/PairDeconstructorAttribute.cs b/src/Spectre.Console/Cli/Annotations/PairDeconstructorAttribute.cs index e842fa6..3575735 100644 --- a/src/Spectre.Console/Cli/Annotations/PairDeconstructorAttribute.cs +++ b/src/Spectre.Console/Cli/Annotations/PairDeconstructorAttribute.cs @@ -1,31 +1,30 @@ using System; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// Specifies what type to use as a pair deconstructor for +/// the property this attribute is bound to. +/// +[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] +public sealed class PairDeconstructorAttribute : Attribute { /// - /// Specifies what type to use as a pair deconstructor for - /// the property this attribute is bound to. + /// Gets the that represents the type of the + /// pair deconstructor class to use for data conversion for the + /// object this attribute is bound to. /// - [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] - public sealed class PairDeconstructorAttribute : Attribute - { - /// - /// Gets the that represents the type of the - /// pair deconstructor class to use for data conversion for the - /// object this attribute is bound to. - /// - public Type Type { get; } + public Type Type { get; } - /// - /// Initializes a new instance of the class. - /// - /// - /// A System.Type that represents the type of the pair deconstructor - /// class to use for data conversion for the object this attribute is bound to. - /// - public PairDeconstructorAttribute(Type type) - { - Type = type ?? throw new ArgumentNullException(nameof(type)); - } + /// + /// Initializes a new instance of the class. + /// + /// + /// A System.Type that represents the type of the pair deconstructor + /// class to use for data conversion for the object this attribute is bound to. + /// + public PairDeconstructorAttribute(Type type) + { + Type = type ?? throw new ArgumentNullException(nameof(type)); } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Annotations/ParameterValidationAttribute.cs b/src/Spectre.Console/Cli/Annotations/ParameterValidationAttribute.cs index 381e7f1..2bd2300 100644 --- a/src/Spectre.Console/Cli/Annotations/ParameterValidationAttribute.cs +++ b/src/Spectre.Console/Cli/Annotations/ParameterValidationAttribute.cs @@ -1,34 +1,33 @@ using System; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// A base class attribute used for parameter validation. +/// +/// +[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)] +public abstract class ParameterValidationAttribute : Attribute { /// - /// A base class attribute used for parameter validation. + /// Gets the validation error message. /// - /// - [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)] - public abstract class ParameterValidationAttribute : Attribute + /// The validation error message. + public string ErrorMessage { get; } + + /// + /// Initializes a new instance of the class. + /// + /// The validation error message. + protected ParameterValidationAttribute(string errorMessage) { - /// - /// Gets the validation error message. - /// - /// The validation error message. - public string ErrorMessage { get; } - - /// - /// Initializes a new instance of the class. - /// - /// The validation error message. - protected ParameterValidationAttribute(string errorMessage) - { - ErrorMessage = errorMessage; - } - - /// - /// Validates the parameter value. - /// - /// The parameter context. - /// The validation result. - public abstract ValidationResult Validate(CommandParameterContext context); + ErrorMessage = errorMessage; } + + /// + /// Validates the parameter value. + /// + /// The parameter context. + /// The validation result. + public abstract ValidationResult Validate(CommandParameterContext context); } \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Annotations/ParameterValueProviderAttribute.cs b/src/Spectre.Console/Cli/Annotations/ParameterValueProviderAttribute.cs index 5dbf410..336f260 100644 --- a/src/Spectre.Console/Cli/Annotations/ParameterValueProviderAttribute.cs +++ b/src/Spectre.Console/Cli/Annotations/ParameterValueProviderAttribute.cs @@ -1,20 +1,19 @@ using System; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// A base class attribute used for parameter completion. +/// +/// +[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] +public abstract class ParameterValueProviderAttribute : Attribute { /// - /// A base class attribute used for parameter completion. + /// Gets a value for the parameter. /// - /// - [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] - public abstract class ParameterValueProviderAttribute : Attribute - { - /// - /// Gets a value for the parameter. - /// - /// The parameter context. - /// The resulting value. - /// true if a value was provided; otherwise, false. - public abstract bool TryGetValue(CommandParameterContext context, out object? result); - } -} + /// The parameter context. + /// The resulting value. + /// true if a value was provided; otherwise, false. + public abstract bool TryGetValue(CommandParameterContext context, out object? result); +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/AsyncCommand.cs b/src/Spectre.Console/Cli/AsyncCommand.cs index 1124ee2..72099b9 100644 --- a/src/Spectre.Console/Cli/AsyncCommand.cs +++ b/src/Spectre.Console/Cli/AsyncCommand.cs @@ -1,35 +1,34 @@ using System.Threading.Tasks; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// Base class for an asynchronous command with no settings. +/// +public abstract class AsyncCommand : ICommand { /// - /// Base class for an asynchronous command with no settings. + /// Executes the command. /// - public abstract class AsyncCommand : ICommand + /// The command context. + /// An integer indicating whether or not the command executed successfully. + public abstract Task ExecuteAsync(CommandContext context); + + /// + Task ICommand.Execute(CommandContext context, EmptyCommandSettings settings) { - /// - /// Executes the command. - /// - /// The command context. - /// An integer indicating whether or not the command executed successfully. - public abstract Task ExecuteAsync(CommandContext context); + return ExecuteAsync(context); + } - /// - Task ICommand.Execute(CommandContext context, EmptyCommandSettings settings) - { - return ExecuteAsync(context); - } + /// + Task ICommand.Execute(CommandContext context, CommandSettings settings) + { + return ExecuteAsync(context); + } - /// - Task ICommand.Execute(CommandContext context, CommandSettings settings) - { - return ExecuteAsync(context); - } - - /// - ValidationResult ICommand.Validate(CommandContext context, CommandSettings settings) - { - return ValidationResult.Success(); - } + /// + ValidationResult ICommand.Validate(CommandContext context, CommandSettings settings) + { + return ValidationResult.Success(); } } \ No newline at end of file diff --git a/src/Spectre.Console/Cli/AsyncCommandOfT.cs b/src/Spectre.Console/Cli/AsyncCommandOfT.cs index f4b8729..80be43d 100644 --- a/src/Spectre.Console/Cli/AsyncCommandOfT.cs +++ b/src/Spectre.Console/Cli/AsyncCommandOfT.cs @@ -1,51 +1,50 @@ using System.Diagnostics; using System.Threading.Tasks; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// Base class for an asynchronous command. +/// +/// The settings type. +public abstract class AsyncCommand : ICommand + where TSettings : CommandSettings { /// - /// Base class for an asynchronous command. + /// Validates the specified settings and remaining arguments. /// - /// The settings type. - public abstract class AsyncCommand : ICommand - where TSettings : CommandSettings + /// The command context. + /// The settings. + /// The validation result. + public virtual ValidationResult Validate(CommandContext context, TSettings settings) { - /// - /// Validates the specified settings and remaining arguments. - /// - /// The command context. - /// The settings. - /// The validation result. - public virtual ValidationResult Validate(CommandContext context, TSettings settings) - { - return ValidationResult.Success(); - } + return ValidationResult.Success(); + } - /// - /// Executes the command. - /// - /// The command context. - /// The settings. - /// An integer indicating whether or not the command executed successfully. - public abstract Task ExecuteAsync(CommandContext context, TSettings settings); + /// + /// Executes the command. + /// + /// The command context. + /// The settings. + /// An integer indicating whether or not the command executed successfully. + public abstract Task ExecuteAsync(CommandContext context, TSettings settings); - /// - ValidationResult ICommand.Validate(CommandContext context, CommandSettings settings) - { - return Validate(context, (TSettings)settings); - } + /// + ValidationResult ICommand.Validate(CommandContext context, CommandSettings settings) + { + return Validate(context, (TSettings)settings); + } - /// - Task ICommand.Execute(CommandContext context, CommandSettings settings) - { - Debug.Assert(settings is TSettings, "Command settings is of unexpected type."); - return ExecuteAsync(context, (TSettings)settings); - } + /// + Task ICommand.Execute(CommandContext context, CommandSettings settings) + { + Debug.Assert(settings is TSettings, "Command settings is of unexpected type."); + return ExecuteAsync(context, (TSettings)settings); + } - /// - Task ICommand.Execute(CommandContext context, TSettings settings) - { - return ExecuteAsync(context, settings); - } + /// + Task ICommand.Execute(CommandContext context, TSettings settings) + { + return ExecuteAsync(context, settings); } } \ No newline at end of file diff --git a/src/Spectre.Console/Cli/CaseSensitivity.cs b/src/Spectre.Console/Cli/CaseSensitivity.cs index e1ee9d4..ce00760 100644 --- a/src/Spectre.Console/Cli/CaseSensitivity.cs +++ b/src/Spectre.Console/Cli/CaseSensitivity.cs @@ -1,31 +1,30 @@ using System; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// Represents case sensitivity. +/// +[Flags] +public enum CaseSensitivity { /// - /// Represents case sensitivity. + /// Nothing is case sensitive. /// - [Flags] - public enum CaseSensitivity - { - /// - /// Nothing is case sensitive. - /// - None = 0, + None = 0, - /// - /// Long options are case sensitive. - /// - LongOptions = 1, + /// + /// Long options are case sensitive. + /// + LongOptions = 1, - /// - /// Commands are case sensitive. - /// - Commands = 2, + /// + /// Commands are case sensitive. + /// + Commands = 2, - /// - /// Everything is case sensitive. - /// - All = LongOptions | Commands, - } -} + /// + /// Everything is case sensitive. + /// + All = LongOptions | Commands, +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Command.cs b/src/Spectre.Console/Cli/Command.cs index 43ac766..4b87fe9 100644 --- a/src/Spectre.Console/Cli/Command.cs +++ b/src/Spectre.Console/Cli/Command.cs @@ -1,36 +1,35 @@ using System.Threading.Tasks; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// Base class for a command without settings. +/// +/// +public abstract class Command : ICommand { /// - /// Base class for a command without settings. + /// Executes the command. /// - /// - public abstract class Command : ICommand + /// The command context. + /// An integer indicating whether or not the command executed successfully. + public abstract int Execute(CommandContext context); + + /// + Task ICommand.Execute(CommandContext context, EmptyCommandSettings settings) { - /// - /// Executes the command. - /// - /// The command context. - /// An integer indicating whether or not the command executed successfully. - public abstract int Execute(CommandContext context); - - /// - Task ICommand.Execute(CommandContext context, EmptyCommandSettings settings) - { - return Task.FromResult(Execute(context)); - } - - /// - Task ICommand.Execute(CommandContext context, CommandSettings settings) - { - return Task.FromResult(Execute(context)); - } - - /// - ValidationResult ICommand.Validate(CommandContext context, CommandSettings settings) - { - return ValidationResult.Success(); - } + return Task.FromResult(Execute(context)); } -} + + /// + Task ICommand.Execute(CommandContext context, CommandSettings settings) + { + return Task.FromResult(Execute(context)); + } + + /// + ValidationResult ICommand.Validate(CommandContext context, CommandSettings settings) + { + return ValidationResult.Success(); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/CommandApp.cs b/src/Spectre.Console/Cli/CommandApp.cs index 392bf44..bb6256d 100644 --- a/src/Spectre.Console/Cli/CommandApp.cs +++ b/src/Spectre.Console/Cli/CommandApp.cs @@ -4,136 +4,136 @@ using System.Diagnostics; using System.Threading.Tasks; using Spectre.Console.Rendering; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// The entry point for a command line application. +/// +public sealed class CommandApp : ICommandApp { + private readonly Configurator _configurator; + private readonly CommandExecutor _executor; + private bool _executed; + /// - /// The entry point for a command line application. + /// Initializes a new instance of the class. /// - public sealed class CommandApp : ICommandApp + /// The registrar. + public CommandApp(ITypeRegistrar? registrar = null) { - private readonly Configurator _configurator; - private readonly CommandExecutor _executor; - private bool _executed; + registrar ??= new DefaultTypeRegistrar(); - /// - /// Initializes a new instance of the class. - /// - /// The registrar. - public CommandApp(ITypeRegistrar? registrar = null) + _configurator = new Configurator(registrar); + _executor = new CommandExecutor(registrar); + } + + /// + /// Configures the command line application. + /// + /// The configuration. + public void Configure(Action configuration) + { + if (configuration == null) { - registrar ??= new DefaultTypeRegistrar(); - - _configurator = new Configurator(registrar); - _executor = new CommandExecutor(registrar); + throw new ArgumentNullException(nameof(configuration)); } - /// - /// Configures the command line application. - /// - /// The configuration. - public void Configure(Action configuration) + configuration(_configurator); + } + + /// + /// Sets the default command. + /// + /// The command type. + public void SetDefaultCommand() + where TCommand : class, ICommand + { + GetConfigurator().SetDefaultCommand(); + } + + /// + /// Runs the command line application with specified arguments. + /// + /// The arguments. + /// The exit code from the executed command. + public int Run(IEnumerable args) + { + return RunAsync(args).GetAwaiter().GetResult(); + } + + /// + /// Runs the command line application with specified arguments. + /// + /// The arguments. + /// The exit code from the executed command. + public async Task RunAsync(IEnumerable args) + { + try { - if (configuration == null) + if (!_executed) { - throw new ArgumentNullException(nameof(configuration)); + // Add built-in (hidden) commands. + _configurator.AddBranch(CliConstants.Commands.Branch, cli => + { + cli.HideBranch(); + cli.AddCommand(CliConstants.Commands.Version); + cli.AddCommand(CliConstants.Commands.XmlDoc); + cli.AddCommand(CliConstants.Commands.Explain); + }); + + _executed = true; } - configuration(_configurator); + return await _executor + .Execute(_configurator, args) + .ConfigureAwait(false); } - - /// - /// Sets the default command. - /// - /// The command type. - public void SetDefaultCommand() - where TCommand : class, ICommand + catch (Exception ex) { - GetConfigurator().SetDefaultCommand(); - } - - /// - /// Runs the command line application with specified arguments. - /// - /// The arguments. - /// The exit code from the executed command. - public int Run(IEnumerable args) - { - return RunAsync(args).GetAwaiter().GetResult(); - } - - /// - /// Runs the command line application with specified arguments. - /// - /// The arguments. - /// The exit code from the executed command. - public async Task RunAsync(IEnumerable args) - { - try + // Should we always propagate when debugging? + if (Debugger.IsAttached + && ex is CommandAppException appException + && appException.AlwaysPropagateWhenDebugging) { - if (!_executed) - { - // Add built-in (hidden) commands. - _configurator.AddBranch(CliConstants.Commands.Branch, cli => - { - cli.HideBranch(); - cli.AddCommand(CliConstants.Commands.Version); - cli.AddCommand(CliConstants.Commands.XmlDoc); - cli.AddCommand(CliConstants.Commands.Explain); - }); - - _executed = true; - } - - return await _executor - .Execute(_configurator, args) - .ConfigureAwait(false); - } - catch (Exception ex) - { - // Should we always propagate when debugging? - if (Debugger.IsAttached - && ex is CommandAppException appException - && appException.AlwaysPropagateWhenDebugging) - { - throw; - } - - if (_configurator.Settings.PropagateExceptions) - { - throw; - } - - if (_configurator.Settings.ExceptionHandler != null) - { - return _configurator.Settings.ExceptionHandler(ex); - } - - // Render the exception. - var pretty = GetRenderableErrorMessage(ex); - if (pretty != null) - { - _configurator.Settings.Console.SafeRender(pretty); - } - - return -1; - } - } - - internal Configurator GetConfigurator() - { - return _configurator; - } - - private static List? GetRenderableErrorMessage(Exception ex, bool convert = true) - { - if (ex is CommandAppException renderable && renderable.Pretty != null) - { - return new List { renderable.Pretty }; + throw; } - if (convert) + if (_configurator.Settings.PropagateExceptions) { - var converted = new List + throw; + } + + if (_configurator.Settings.ExceptionHandler != null) + { + return _configurator.Settings.ExceptionHandler(ex); + } + + // Render the exception. + var pretty = GetRenderableErrorMessage(ex); + if (pretty != null) + { + _configurator.Settings.Console.SafeRender(pretty); + } + + return -1; + } + } + + internal Configurator GetConfigurator() + { + return _configurator; + } + + private static List? GetRenderableErrorMessage(Exception ex, bool convert = true) + { + if (ex is CommandAppException renderable && renderable.Pretty != null) + { + return new List { renderable.Pretty }; + } + + if (convert) + { + var converted = new List { new Composer() .Text("[red]Error:[/]") @@ -142,20 +142,19 @@ namespace Spectre.Console.Cli .LineBreak(), }; - // Got a renderable inner exception? - if (ex.InnerException != null) + // Got a renderable inner exception? + if (ex.InnerException != null) + { + var innerRenderable = GetRenderableErrorMessage(ex.InnerException, convert: false); + if (innerRenderable != null) { - var innerRenderable = GetRenderableErrorMessage(ex.InnerException, convert: false); - if (innerRenderable != null) - { - converted.AddRange(innerRenderable); - } + converted.AddRange(innerRenderable); } - - return converted; } - return null; + return converted; } + + return null; } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/CommandAppException.cs b/src/Spectre.Console/Cli/CommandAppException.cs index 7d0ef6f..f3d4fe3 100644 --- a/src/Spectre.Console/Cli/CommandAppException.cs +++ b/src/Spectre.Console/Cli/CommandAppException.cs @@ -1,30 +1,29 @@ using System; using Spectre.Console.Rendering; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// Represents errors that occur during application execution. +/// +public abstract class CommandAppException : Exception { /// - /// Represents errors that occur during application execution. + /// Gets the pretty formatted exception message. /// - public abstract class CommandAppException : Exception + public IRenderable? Pretty { get; } + + internal virtual bool AlwaysPropagateWhenDebugging => false; + + internal CommandAppException(string message, IRenderable? pretty = null) + : base(message) { - /// - /// Gets the pretty formatted exception message. - /// - public IRenderable? Pretty { get; } + Pretty = pretty; + } - internal virtual bool AlwaysPropagateWhenDebugging => false; - - internal CommandAppException(string message, IRenderable? pretty = null) - : base(message) - { - Pretty = pretty; - } - - internal CommandAppException(string message, Exception ex, IRenderable? pretty = null) - : base(message, ex) - { - Pretty = pretty; - } + internal CommandAppException(string message, Exception ex, IRenderable? pretty = null) + : base(message, ex) + { + Pretty = pretty; } } \ No newline at end of file diff --git a/src/Spectre.Console/Cli/CommandAppOfT.cs b/src/Spectre.Console/Cli/CommandAppOfT.cs index 76dd347..05befdd 100644 --- a/src/Spectre.Console/Cli/CommandAppOfT.cs +++ b/src/Spectre.Console/Cli/CommandAppOfT.cs @@ -2,54 +2,53 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// The entry point for a command line application with a default command. +/// +/// The type of the default command. +public sealed class CommandApp : ICommandApp + where TDefaultCommand : class, ICommand { + private readonly CommandApp _app; + /// - /// The entry point for a command line application with a default command. + /// Initializes a new instance of the class. /// - /// The type of the default command. - public sealed class CommandApp : ICommandApp - where TDefaultCommand : class, ICommand + /// The registrar. + public CommandApp(ITypeRegistrar? registrar = null) { - private readonly CommandApp _app; - - /// - /// Initializes a new instance of the class. - /// - /// The registrar. - public CommandApp(ITypeRegistrar? registrar = null) - { - _app = new CommandApp(registrar); - _app.GetConfigurator().SetDefaultCommand(); - } - - /// - /// Configures the command line application. - /// - /// The configuration. - public void Configure(Action configuration) - { - _app.Configure(configuration); - } - - /// - /// Runs the command line application with specified arguments. - /// - /// The arguments. - /// The exit code from the executed command. - public int Run(IEnumerable args) - { - return _app.Run(args); - } - - /// - /// Runs the command line application with specified arguments. - /// - /// The arguments. - /// The exit code from the executed command. - public Task RunAsync(IEnumerable args) - { - return _app.RunAsync(args); - } + _app = new CommandApp(registrar); + _app.GetConfigurator().SetDefaultCommand(); } -} + + /// + /// Configures the command line application. + /// + /// The configuration. + public void Configure(Action configuration) + { + _app.Configure(configuration); + } + + /// + /// Runs the command line application with specified arguments. + /// + /// The arguments. + /// The exit code from the executed command. + public int Run(IEnumerable args) + { + return _app.Run(args); + } + + /// + /// Runs the command line application with specified arguments. + /// + /// The arguments. + /// The exit code from the executed command. + public Task RunAsync(IEnumerable args) + { + return _app.RunAsync(args); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/CommandConfigurationException.cs b/src/Spectre.Console/Cli/CommandConfigurationException.cs index 3f6dce3..0bd43bc 100644 --- a/src/Spectre.Console/Cli/CommandConfigurationException.cs +++ b/src/Spectre.Console/Cli/CommandConfigurationException.cs @@ -2,80 +2,79 @@ using System; using System.Linq; using Spectre.Console.Rendering; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// Represents errors that occur during configuration. +/// +public class CommandConfigurationException : CommandAppException { - /// - /// Represents errors that occur during configuration. - /// - public class CommandConfigurationException : CommandAppException + internal override bool AlwaysPropagateWhenDebugging => true; + + internal CommandConfigurationException(string message, IRenderable? pretty = null) + : base(message, pretty) { - internal override bool AlwaysPropagateWhenDebugging => true; - - internal CommandConfigurationException(string message, IRenderable? pretty = null) - : base(message, pretty) - { - } - - internal CommandConfigurationException(string message, Exception ex, IRenderable? pretty = null) - : base(message, ex, pretty) - { - } - - internal static CommandConfigurationException NoCommandConfigured() - { - return new CommandConfigurationException("No commands have been configured."); - } - - internal static CommandConfigurationException CommandNameConflict(CommandInfo command, string alias) - { - return new CommandConfigurationException($"The alias '{alias}' for '{command.Name}' conflicts with another command."); - } - - internal static CommandConfigurationException DuplicateOption(CommandInfo command, string[] options) - { - var keys = string.Join(", ", options.Select(x => x.Length > 1 ? $"--{x}" : $"-{x}")); - if (options.Length > 1) - { - return new CommandConfigurationException($"Options {keys} are duplicated in command '{command.Name}'."); - } - - return new CommandConfigurationException($"Option {keys} is duplicated in command '{command.Name}'."); - } - - internal static CommandConfigurationException BranchHasNoChildren(CommandInfo command) - { - throw new CommandConfigurationException($"The branch '{command.Name}' does not define any commands."); - } - - internal static CommandConfigurationException TooManyVectorArguments(CommandInfo command) - { - throw new CommandConfigurationException($"The command '{command.Name}' specifies more than one vector argument."); - } - - internal static CommandConfigurationException VectorArgumentNotSpecifiedLast(CommandInfo command) - { - throw new CommandConfigurationException($"The command '{command.Name}' specifies an argument vector that is not the last argument."); - } - - internal static CommandConfigurationException OptionalOptionValueMustBeFlagWithValue(CommandOption option) - { - return new CommandConfigurationException($"The option '{option.GetOptionName()}' has an optional value but does not implement IFlagValue."); - } - - internal static CommandConfigurationException OptionBothHasPairDeconstructorAndTypeParameter(CommandOption option) - { - return new CommandConfigurationException($"The option '{option.GetOptionName()}' is both marked as pair deconstructable and convertable."); - } - - internal static CommandConfigurationException OptionTypeDoesNotSupportDeconstruction(CommandOption option) - { - return new CommandConfigurationException($"The option '{option.GetOptionName()}' is marked as " + - "pair deconstructable, but the underlying type does not support that."); - } - - internal static CommandConfigurationException RequiredArgumentsCannotHaveDefaultValue(CommandArgument option) - { - return new CommandConfigurationException($"The required argument '{option.Value}' cannot have a default value."); - } } -} + + internal CommandConfigurationException(string message, Exception ex, IRenderable? pretty = null) + : base(message, ex, pretty) + { + } + + internal static CommandConfigurationException NoCommandConfigured() + { + return new CommandConfigurationException("No commands have been configured."); + } + + internal static CommandConfigurationException CommandNameConflict(CommandInfo command, string alias) + { + return new CommandConfigurationException($"The alias '{alias}' for '{command.Name}' conflicts with another command."); + } + + internal static CommandConfigurationException DuplicateOption(CommandInfo command, string[] options) + { + var keys = string.Join(", ", options.Select(x => x.Length > 1 ? $"--{x}" : $"-{x}")); + if (options.Length > 1) + { + return new CommandConfigurationException($"Options {keys} are duplicated in command '{command.Name}'."); + } + + return new CommandConfigurationException($"Option {keys} is duplicated in command '{command.Name}'."); + } + + internal static CommandConfigurationException BranchHasNoChildren(CommandInfo command) + { + throw new CommandConfigurationException($"The branch '{command.Name}' does not define any commands."); + } + + internal static CommandConfigurationException TooManyVectorArguments(CommandInfo command) + { + throw new CommandConfigurationException($"The command '{command.Name}' specifies more than one vector argument."); + } + + internal static CommandConfigurationException VectorArgumentNotSpecifiedLast(CommandInfo command) + { + throw new CommandConfigurationException($"The command '{command.Name}' specifies an argument vector that is not the last argument."); + } + + internal static CommandConfigurationException OptionalOptionValueMustBeFlagWithValue(CommandOption option) + { + return new CommandConfigurationException($"The option '{option.GetOptionName()}' has an optional value but does not implement IFlagValue."); + } + + internal static CommandConfigurationException OptionBothHasPairDeconstructorAndTypeParameter(CommandOption option) + { + return new CommandConfigurationException($"The option '{option.GetOptionName()}' is both marked as pair deconstructable and convertable."); + } + + internal static CommandConfigurationException OptionTypeDoesNotSupportDeconstruction(CommandOption option) + { + return new CommandConfigurationException($"The option '{option.GetOptionName()}' is marked as " + + "pair deconstructable, but the underlying type does not support that."); + } + + internal static CommandConfigurationException RequiredArgumentsCannotHaveDefaultValue(CommandArgument option) + { + return new CommandConfigurationException($"The required argument '{option.Value}' cannot have a default value."); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/CommandContext.cs b/src/Spectre.Console/Cli/CommandContext.cs index 13bc96c..c175ec4 100644 --- a/src/Spectre.Console/Cli/CommandContext.cs +++ b/src/Spectre.Console/Cli/CommandContext.cs @@ -1,45 +1,44 @@ -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// Represents a command context. +/// +public sealed class CommandContext { /// - /// Represents a command context. + /// Gets the remaining arguments. /// - public sealed class CommandContext + /// + /// The remaining arguments. + /// + public IRemainingArguments Remaining { get; } + + /// + /// Gets the name of the command. + /// + /// + /// The name of the command. + /// + public string Name { get; } + + /// + /// Gets the data that was passed to the command during registration (if any). + /// + /// + /// The command data. + /// + public object? Data { get; } + + /// + /// Initializes a new instance of the class. + /// + /// The remaining arguments. + /// The command name. + /// The command data. + public CommandContext(IRemainingArguments remaining, string name, object? data) { - /// - /// Gets the remaining arguments. - /// - /// - /// The remaining arguments. - /// - public IRemainingArguments Remaining { get; } - - /// - /// Gets the name of the command. - /// - /// - /// The name of the command. - /// - public string Name { get; } - - /// - /// Gets the data that was passed to the command during registration (if any). - /// - /// - /// The command data. - /// - public object? Data { get; } - - /// - /// Initializes a new instance of the class. - /// - /// The remaining arguments. - /// The command name. - /// The command data. - public CommandContext(IRemainingArguments remaining, string name, object? data) - { - Remaining = remaining ?? throw new System.ArgumentNullException(nameof(remaining)); - Name = name ?? throw new System.ArgumentNullException(nameof(name)); - Data = data; - } + Remaining = remaining ?? throw new System.ArgumentNullException(nameof(remaining)); + Name = name ?? throw new System.ArgumentNullException(nameof(name)); + Data = data; } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/CommandOfT.cs b/src/Spectre.Console/Cli/CommandOfT.cs index 775e38f..57833b2 100644 --- a/src/Spectre.Console/Cli/CommandOfT.cs +++ b/src/Spectre.Console/Cli/CommandOfT.cs @@ -2,52 +2,51 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// Base class for a command. +/// +/// The settings type. +/// +public abstract class Command : ICommand + where TSettings : CommandSettings { /// - /// Base class for a command. + /// Validates the specified settings and remaining arguments. /// - /// The settings type. - /// - public abstract class Command : ICommand - where TSettings : CommandSettings + /// The command context. + /// The settings. + /// The validation result. + public virtual ValidationResult Validate([NotNull] CommandContext context, [NotNull] TSettings settings) { - /// - /// Validates the specified settings and remaining arguments. - /// - /// The command context. - /// The settings. - /// The validation result. - public virtual ValidationResult Validate([NotNull] CommandContext context, [NotNull] TSettings settings) - { - return ValidationResult.Success(); - } - - /// - /// Executes the command. - /// - /// The command context. - /// The settings. - /// An integer indicating whether or not the command executed successfully. - public abstract int Execute([NotNull] CommandContext context, [NotNull] TSettings settings); - - /// - ValidationResult ICommand.Validate(CommandContext context, CommandSettings settings) - { - return Validate(context, (TSettings)settings); - } - - /// - Task ICommand.Execute(CommandContext context, CommandSettings settings) - { - Debug.Assert(settings is TSettings, "Command settings is of unexpected type."); - return Task.FromResult(Execute(context, (TSettings)settings)); - } - - /// - Task ICommand.Execute(CommandContext context, TSettings settings) - { - return Task.FromResult(Execute(context, settings)); - } + return ValidationResult.Success(); } -} + + /// + /// Executes the command. + /// + /// The command context. + /// The settings. + /// An integer indicating whether or not the command executed successfully. + public abstract int Execute([NotNull] CommandContext context, [NotNull] TSettings settings); + + /// + ValidationResult ICommand.Validate(CommandContext context, CommandSettings settings) + { + return Validate(context, (TSettings)settings); + } + + /// + Task ICommand.Execute(CommandContext context, CommandSettings settings) + { + Debug.Assert(settings is TSettings, "Command settings is of unexpected type."); + return Task.FromResult(Execute(context, (TSettings)settings)); + } + + /// + Task ICommand.Execute(CommandContext context, TSettings settings) + { + return Task.FromResult(Execute(context, settings)); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/CommandParameterContext.cs b/src/Spectre.Console/Cli/CommandParameterContext.cs index 658f37a..442abdd 100644 --- a/src/Spectre.Console/Cli/CommandParameterContext.cs +++ b/src/Spectre.Console/Cli/CommandParameterContext.cs @@ -1,38 +1,37 @@ using System; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// Represents a context for related operations. +/// +public sealed class CommandParameterContext { /// - /// Represents a context for related operations. + /// Gets the parameter. /// - public sealed class CommandParameterContext + public ICommandParameterInfo Parameter { get; } + + /// + /// Gets the type resolver. + /// + public ITypeResolver Resolver { get; } + + /// + /// Gets tje parameter value. + /// + public object? Value { get; } + + /// + /// Initializes a new instance of the class. + /// + /// The parameter. + /// The type resolver. + /// The parameter value. + public CommandParameterContext(ICommandParameterInfo parameter, ITypeResolver resolver, object? value) { - /// - /// Gets the parameter. - /// - public ICommandParameterInfo Parameter { get; } - - /// - /// Gets the type resolver. - /// - public ITypeResolver Resolver { get; } - - /// - /// Gets tje parameter value. - /// - public object? Value { get; } - - /// - /// Initializes a new instance of the class. - /// - /// The parameter. - /// The type resolver. - /// The parameter value. - public CommandParameterContext(ICommandParameterInfo parameter, ITypeResolver resolver, object? value) - { - Parameter = parameter ?? throw new ArgumentNullException(nameof(parameter)); - Resolver = resolver ?? throw new ArgumentNullException(nameof(resolver)); - Value = value; - } + Parameter = parameter ?? throw new ArgumentNullException(nameof(parameter)); + Resolver = resolver ?? throw new ArgumentNullException(nameof(resolver)); + Value = value; } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/CommandParseException.cs b/src/Spectre.Console/Cli/CommandParseException.cs index 00c2c81..589554a 100644 --- a/src/Spectre.Console/Cli/CommandParseException.cs +++ b/src/Spectre.Console/Cli/CommandParseException.cs @@ -3,125 +3,124 @@ using System.Collections.Generic; using System.Globalization; using Spectre.Console.Rendering; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// Represents errors that occur during parsing. +/// +public sealed class CommandParseException : CommandRuntimeException { - /// - /// Represents errors that occur during parsing. - /// - public sealed class CommandParseException : CommandRuntimeException + internal CommandParseException(string message, IRenderable? pretty = null) + : base(message, pretty) { - internal CommandParseException(string message, IRenderable? pretty = null) - : base(message, pretty) - { - } - - internal static CommandParseException CouldNotCreateSettings(Type settingsType) - { - return new CommandParseException($"Could not create settings of type '{settingsType.FullName}'."); - } - - internal static CommandParseException CouldNotCreateCommand(Type? commandType) - { - if (commandType == null) - { - return new CommandParseException($"Could not create command. Command type is unknown."); - } - - return new CommandParseException($"Could not create command of type '{commandType.FullName}'."); - } - - internal static CommandParseException ExpectedTokenButFoundNull(CommandTreeToken.Kind expected) - { - return new CommandParseException($"Expected to find any token of type '{expected}' but found null instead."); - } - - internal static CommandParseException ExpectedTokenButFoundOther(CommandTreeToken.Kind expected, CommandTreeToken.Kind found) - { - return new CommandParseException($"Expected to find token of type '{expected}' but found '{found}' instead."); - } - - internal static CommandParseException OptionHasNoName(string input, CommandTreeToken token) - { - return CommandLineParseExceptionFactory.Create(input, token, "Option does not have a name.", "Did you forget the option name?"); - } - - internal static CommandParseException OptionValueWasExpected(string input, CommandTreeToken token) - { - return CommandLineParseExceptionFactory.Create(input, token, "Expected an option value.", "Did you forget the option value?"); - } - - internal static CommandParseException OptionHasNoValue(IEnumerable args, CommandTreeToken token, CommandOption option) - { - return CommandLineParseExceptionFactory.Create(args, token, $"Option '{option.GetOptionName()}' is defined but no value has been provided.", "No value provided."); - } - - internal static CommandParseException UnexpectedOption(IEnumerable args, CommandTreeToken token) - { - return CommandLineParseExceptionFactory.Create(args, token, $"Unexpected option '{token.Value}'.", "Did you forget the command?"); - } - - internal static CommandParseException CannotAssignValueToFlag(IEnumerable args, CommandTreeToken token) - { - return CommandLineParseExceptionFactory.Create(args, token, "Flags cannot be assigned a value.", "Can't assign value."); - } - - internal static CommandParseException InvalidShortOptionName(string input, CommandTreeToken token) - { - return CommandLineParseExceptionFactory.Create(input, token, "Short option does not have a valid name.", "Not a valid name for a short option."); - } - - internal static CommandParseException LongOptionNameIsMissing(TextBuffer reader, int position) - { - var token = new CommandTreeToken(CommandTreeToken.Kind.LongOption, position, string.Empty, "--"); - return CommandLineParseExceptionFactory.Create(reader.Original, token, "Invalid long option name.", "Did you forget the option name?"); - } - - internal static CommandParseException LongOptionNameIsOneCharacter(TextBuffer reader, int position, string name) - { - var token = new CommandTreeToken(CommandTreeToken.Kind.LongOption, position, name, $"--{name}"); - var reason = $"Did you mean -{name}?"; - return CommandLineParseExceptionFactory.Create(reader.Original, token, "Invalid long option name.", reason); - } - - internal static CommandParseException LongOptionNameStartWithDigit(TextBuffer reader, int position, string name) - { - var token = new CommandTreeToken(CommandTreeToken.Kind.LongOption, position, name, $"--{name}"); - return CommandLineParseExceptionFactory.Create(reader.Original, token, "Invalid long option name.", "Option names cannot start with a digit."); - } - - internal static CommandParseException LongOptionNameContainSymbol(TextBuffer reader, int position, char character) - { - var name = character.ToString(CultureInfo.InvariantCulture); - var token = new CommandTreeToken(CommandTreeToken.Kind.LongOption, position, name, name); - return CommandLineParseExceptionFactory.Create(reader.Original, token, "Invalid long option name.", "Invalid character."); - } - - internal static CommandParseException UnterminatedQuote(string input, CommandTreeToken token) - { - return CommandLineParseExceptionFactory.Create(input, token, $"Encountered unterminated quoted string '{token.Value}'.", "Did you forget the closing quotation mark?"); - } - - internal static CommandParseException UnknownCommand(CommandModel model, CommandTree? node, IEnumerable args, CommandTreeToken token) - { - var suggestion = CommandSuggestor.Suggest(model, node?.Command, token.Value); - var text = suggestion != null ? $"Did you mean '{suggestion.Name}'?" : "No such command."; - return CommandLineParseExceptionFactory.Create(args, token, $"Unknown command '{token.Value}'.", text); - } - - internal static CommandParseException CouldNotMatchArgument(IEnumerable args, CommandTreeToken token) - { - return CommandLineParseExceptionFactory.Create(args, token, $"Could not match '{token.Value}' with an argument.", "Could not match to argument."); - } - - internal static CommandParseException UnknownOption(IEnumerable args, CommandTreeToken token) - { - return CommandLineParseExceptionFactory.Create(args, token, $"Unknown option '{token.Value}'.", "Unknown option."); - } - - internal static CommandParseException ValueIsNotInValidFormat(string value) - { - var text = $"[red]Error:[/] The value '[white]{value}[/]' is not in a correct format"; - return new CommandParseException("Could not parse value", new Markup(text)); - } } -} + + internal static CommandParseException CouldNotCreateSettings(Type settingsType) + { + return new CommandParseException($"Could not create settings of type '{settingsType.FullName}'."); + } + + internal static CommandParseException CouldNotCreateCommand(Type? commandType) + { + if (commandType == null) + { + return new CommandParseException($"Could not create command. Command type is unknown."); + } + + return new CommandParseException($"Could not create command of type '{commandType.FullName}'."); + } + + internal static CommandParseException ExpectedTokenButFoundNull(CommandTreeToken.Kind expected) + { + return new CommandParseException($"Expected to find any token of type '{expected}' but found null instead."); + } + + internal static CommandParseException ExpectedTokenButFoundOther(CommandTreeToken.Kind expected, CommandTreeToken.Kind found) + { + return new CommandParseException($"Expected to find token of type '{expected}' but found '{found}' instead."); + } + + internal static CommandParseException OptionHasNoName(string input, CommandTreeToken token) + { + return CommandLineParseExceptionFactory.Create(input, token, "Option does not have a name.", "Did you forget the option name?"); + } + + internal static CommandParseException OptionValueWasExpected(string input, CommandTreeToken token) + { + return CommandLineParseExceptionFactory.Create(input, token, "Expected an option value.", "Did you forget the option value?"); + } + + internal static CommandParseException OptionHasNoValue(IEnumerable args, CommandTreeToken token, CommandOption option) + { + return CommandLineParseExceptionFactory.Create(args, token, $"Option '{option.GetOptionName()}' is defined but no value has been provided.", "No value provided."); + } + + internal static CommandParseException UnexpectedOption(IEnumerable args, CommandTreeToken token) + { + return CommandLineParseExceptionFactory.Create(args, token, $"Unexpected option '{token.Value}'.", "Did you forget the command?"); + } + + internal static CommandParseException CannotAssignValueToFlag(IEnumerable args, CommandTreeToken token) + { + return CommandLineParseExceptionFactory.Create(args, token, "Flags cannot be assigned a value.", "Can't assign value."); + } + + internal static CommandParseException InvalidShortOptionName(string input, CommandTreeToken token) + { + return CommandLineParseExceptionFactory.Create(input, token, "Short option does not have a valid name.", "Not a valid name for a short option."); + } + + internal static CommandParseException LongOptionNameIsMissing(TextBuffer reader, int position) + { + var token = new CommandTreeToken(CommandTreeToken.Kind.LongOption, position, string.Empty, "--"); + return CommandLineParseExceptionFactory.Create(reader.Original, token, "Invalid long option name.", "Did you forget the option name?"); + } + + internal static CommandParseException LongOptionNameIsOneCharacter(TextBuffer reader, int position, string name) + { + var token = new CommandTreeToken(CommandTreeToken.Kind.LongOption, position, name, $"--{name}"); + var reason = $"Did you mean -{name}?"; + return CommandLineParseExceptionFactory.Create(reader.Original, token, "Invalid long option name.", reason); + } + + internal static CommandParseException LongOptionNameStartWithDigit(TextBuffer reader, int position, string name) + { + var token = new CommandTreeToken(CommandTreeToken.Kind.LongOption, position, name, $"--{name}"); + return CommandLineParseExceptionFactory.Create(reader.Original, token, "Invalid long option name.", "Option names cannot start with a digit."); + } + + internal static CommandParseException LongOptionNameContainSymbol(TextBuffer reader, int position, char character) + { + var name = character.ToString(CultureInfo.InvariantCulture); + var token = new CommandTreeToken(CommandTreeToken.Kind.LongOption, position, name, name); + return CommandLineParseExceptionFactory.Create(reader.Original, token, "Invalid long option name.", "Invalid character."); + } + + internal static CommandParseException UnterminatedQuote(string input, CommandTreeToken token) + { + return CommandLineParseExceptionFactory.Create(input, token, $"Encountered unterminated quoted string '{token.Value}'.", "Did you forget the closing quotation mark?"); + } + + internal static CommandParseException UnknownCommand(CommandModel model, CommandTree? node, IEnumerable args, CommandTreeToken token) + { + var suggestion = CommandSuggestor.Suggest(model, node?.Command, token.Value); + var text = suggestion != null ? $"Did you mean '{suggestion.Name}'?" : "No such command."; + return CommandLineParseExceptionFactory.Create(args, token, $"Unknown command '{token.Value}'.", text); + } + + internal static CommandParseException CouldNotMatchArgument(IEnumerable args, CommandTreeToken token) + { + return CommandLineParseExceptionFactory.Create(args, token, $"Could not match '{token.Value}' with an argument.", "Could not match to argument."); + } + + internal static CommandParseException UnknownOption(IEnumerable args, CommandTreeToken token) + { + return CommandLineParseExceptionFactory.Create(args, token, $"Unknown option '{token.Value}'.", "Unknown option."); + } + + internal static CommandParseException ValueIsNotInValidFormat(string value) + { + var text = $"[red]Error:[/] The value '[white]{value}[/]' is not in a correct format"; + return new CommandParseException("Could not parse value", new Markup(text)); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/CommandRuntimeException.cs b/src/Spectre.Console/Cli/CommandRuntimeException.cs index f498ac4..413e345 100644 --- a/src/Spectre.Console/Cli/CommandRuntimeException.cs +++ b/src/Spectre.Console/Cli/CommandRuntimeException.cs @@ -1,58 +1,57 @@ using System; using Spectre.Console.Rendering; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// Represents errors that occur during runtime. +/// +public class CommandRuntimeException : CommandAppException { - /// - /// Represents errors that occur during runtime. - /// - public class CommandRuntimeException : CommandAppException + internal CommandRuntimeException(string message, IRenderable? pretty = null) + : base(message, pretty) { - internal CommandRuntimeException(string message, IRenderable? pretty = null) - : base(message, pretty) - { - } - - internal CommandRuntimeException(string message, Exception ex, IRenderable? pretty = null) - : base(message, ex, pretty) - { - } - - internal static CommandRuntimeException CouldNotResolveType(Type type, Exception? ex = null) - { - var message = $"Could not resolve type '{type.FullName}'."; - if (ex != null) - { - // TODO: Show internal stuff here. - return new CommandRuntimeException(message, ex); - } - - return new CommandRuntimeException(message); - } - - internal static CommandRuntimeException MissingRequiredArgument(CommandTree node, CommandArgument argument) - { - if (node.Command.Name == CliConstants.DefaultCommandName) - { - return new CommandRuntimeException($"Missing required argument '{argument.Value}'."); - } - - return new CommandRuntimeException($"Command '{node.Command.Name}' is missing required argument '{argument.Value}'."); - } - - internal static CommandRuntimeException NoConverterFound(CommandParameter parameter) - { - return new CommandRuntimeException($"Could not find converter for type '{parameter.ParameterType.FullName}'."); - } - - internal static CommandRuntimeException ValidationFailed(ValidationResult result) - { - return new CommandRuntimeException(result.Message ?? "Unknown validation error."); - } - - internal static Exception CouldNotGetSettingsType(Type commandType) - { - return new CommandRuntimeException($"Could not get settings type for command of type '{commandType.FullName}'."); - } } -} + + internal CommandRuntimeException(string message, Exception ex, IRenderable? pretty = null) + : base(message, ex, pretty) + { + } + + internal static CommandRuntimeException CouldNotResolveType(Type type, Exception? ex = null) + { + var message = $"Could not resolve type '{type.FullName}'."; + if (ex != null) + { + // TODO: Show internal stuff here. + return new CommandRuntimeException(message, ex); + } + + return new CommandRuntimeException(message); + } + + internal static CommandRuntimeException MissingRequiredArgument(CommandTree node, CommandArgument argument) + { + if (node.Command.Name == CliConstants.DefaultCommandName) + { + return new CommandRuntimeException($"Missing required argument '{argument.Value}'."); + } + + return new CommandRuntimeException($"Command '{node.Command.Name}' is missing required argument '{argument.Value}'."); + } + + internal static CommandRuntimeException NoConverterFound(CommandParameter parameter) + { + return new CommandRuntimeException($"Could not find converter for type '{parameter.ParameterType.FullName}'."); + } + + internal static CommandRuntimeException ValidationFailed(ValidationResult result) + { + return new CommandRuntimeException(result.Message ?? "Unknown validation error."); + } + + internal static Exception CouldNotGetSettingsType(Type commandType) + { + return new CommandRuntimeException($"Could not get settings type for command of type '{commandType.FullName}'."); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/CommandSettings.cs b/src/Spectre.Console/Cli/CommandSettings.cs index 131b682..a6edea6 100644 --- a/src/Spectre.Console/Cli/CommandSettings.cs +++ b/src/Spectre.Console/Cli/CommandSettings.cs @@ -1,17 +1,16 @@ -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// Base class for command settings. +/// +public abstract class CommandSettings { /// - /// Base class for command settings. + /// Performs validation of the settings. /// - public abstract class CommandSettings + /// The validation result. + public virtual ValidationResult Validate() { - /// - /// Performs validation of the settings. - /// - /// The validation result. - public virtual ValidationResult Validate() - { - return ValidationResult.Success(); - } + return ValidationResult.Success(); } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/CommandTemplateException.cs b/src/Spectre.Console/Cli/CommandTemplateException.cs index 0d31bca..b9946cc 100644 --- a/src/Spectre.Console/Cli/CommandTemplateException.cs +++ b/src/Spectre.Console/Cli/CommandTemplateException.cs @@ -1,160 +1,159 @@ using System.Globalization; using Spectre.Console.Rendering; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// Represents errors related to parameter templates. +/// +public sealed class CommandTemplateException : CommandConfigurationException { /// - /// Represents errors related to parameter templates. + /// Gets the template that contains the error. /// - public sealed class CommandTemplateException : CommandConfigurationException + public string Template { get; } + + internal override bool AlwaysPropagateWhenDebugging => true; + + internal CommandTemplateException(string message, string template, IRenderable pretty) + : base(message, pretty) { - /// - /// Gets the template that contains the error. - /// - public string Template { get; } - - internal override bool AlwaysPropagateWhenDebugging => true; - - internal CommandTemplateException(string message, string template, IRenderable pretty) - : base(message, pretty) - { - Template = template; - } - - internal static CommandTemplateException UnexpectedCharacter(string template, int position, char character) - { - return CommandLineTemplateExceptionFactory.Create( - template, - new TemplateToken(TemplateToken.Kind.Unknown, position, $"{character}", $"{character}"), - $"Encountered unexpected character '{character}'.", - "Unexpected character."); - } - - internal static CommandTemplateException UnterminatedValueName(string template, TemplateToken token) - { - return CommandLineTemplateExceptionFactory.Create( - template, token, - $"Encountered unterminated value name '{token.Value}'.", - "Unterminated value name."); - } - - internal static CommandTemplateException ArgumentCannotContainOptions(string template, TemplateToken token) - { - return CommandLineTemplateExceptionFactory.Create( - template, token, - "Arguments can not contain options.", - "Not permitted."); - } - - internal static CommandTemplateException MultipleValuesAreNotSupported(string template, TemplateToken token) - { - return CommandLineTemplateExceptionFactory.Create(template, token, - "Multiple values are not supported.", - "Too many values."); - } - - internal static CommandTemplateException ValuesMustHaveName(string template, TemplateToken token) - { - return CommandLineTemplateExceptionFactory.Create(template, token, - "Values without name are not allowed.", - "Missing value name."); - } - - internal static CommandTemplateException OptionsMustHaveName(string template, TemplateToken token) - { - return CommandLineTemplateExceptionFactory.Create(template, token, - "Options without name are not allowed.", - "Missing option name."); - } - - internal static CommandTemplateException OptionNamesCannotStartWithDigit(string template, TemplateToken token) - { - // Rewrite the token to point to the option name instead of the whole string. - token = new TemplateToken( - token.TokenKind, - token.TokenKind == TemplateToken.Kind.ShortName ? token.Position + 1 : token.Position + 2, - token.Value, token.Value); - - return CommandLineTemplateExceptionFactory.Create(template, token, - "Option names cannot start with a digit.", - "Invalid option name."); - } - - internal static CommandTemplateException InvalidCharacterInOptionName(string template, TemplateToken token, char character) - { - // Rewrite the token to point to the invalid character instead of the whole value. - var position = (token.TokenKind == TemplateToken.Kind.ShortName - ? token.Position + 1 - : token.Position + 2) + token.Value.OrdinalIndexOf(character); - - token = new TemplateToken( - token.TokenKind, position, - token.Value, character.ToString(CultureInfo.InvariantCulture)); - - return CommandLineTemplateExceptionFactory.Create(template, token, - $"Encountered invalid character '{character}' in option name.", - "Invalid character."); - } - - internal static CommandTemplateException LongOptionMustHaveMoreThanOneCharacter(string template, TemplateToken token) - { - // Rewrite the token to point to the option name instead of the whole option. - token = new TemplateToken(token.TokenKind, token.Position + 2, token.Value, token.Value); - - return CommandLineTemplateExceptionFactory.Create(template, token, - "Long option names must consist of more than one character.", - "Invalid option name."); - } - - internal static CommandTemplateException MultipleShortOptionNamesNotAllowed(string template, TemplateToken token) - { - return CommandLineTemplateExceptionFactory.Create(template, token, - "Multiple short option names are not supported.", - "Too many short options."); - } - - internal static CommandTemplateException ShortOptionMustOnlyBeOneCharacter(string template, TemplateToken token) - { - // Rewrite the token to point to the option name instead of the whole option. - token = new TemplateToken(token.TokenKind, token.Position + 1, token.Value, token.Value); - - return CommandLineTemplateExceptionFactory.Create(template, token, - "Short option names can not be longer than one character.", - "Invalid option name."); - } - - internal static CommandTemplateException MultipleOptionValuesAreNotSupported(string template, TemplateToken token) - { - return CommandLineTemplateExceptionFactory.Create(template, token, - "Multiple option values are not supported.", - "Too many option values."); - } - - internal static CommandTemplateException InvalidCharacterInValueName(string template, TemplateToken token, char character) - { - // Rewrite the token to point to the invalid character instead of the whole value. - token = new TemplateToken( - token.TokenKind, - token.Position + 1 + token.Value.OrdinalIndexOf(character), - token.Value, character.ToString(CultureInfo.InvariantCulture)); - - return CommandLineTemplateExceptionFactory.Create(template, token, - $"Encountered invalid character '{character}' in value name.", - "Invalid character."); - } - - internal static CommandTemplateException MissingLongAndShortName(string template, TemplateToken? token) - { - return CommandLineTemplateExceptionFactory.Create(template, token, - "No long or short name for option has been specified.", - "Missing option. Was this meant to be an argument?"); - } - - internal static CommandTemplateException ArgumentsMustHaveValueName(string template) - { - return CommandLineTemplateExceptionFactory.Create(template, null, - "Arguments must have a value name.", - "Missing value name."); - } + Template = template; } -} + + internal static CommandTemplateException UnexpectedCharacter(string template, int position, char character) + { + return CommandLineTemplateExceptionFactory.Create( + template, + new TemplateToken(TemplateToken.Kind.Unknown, position, $"{character}", $"{character}"), + $"Encountered unexpected character '{character}'.", + "Unexpected character."); + } + + internal static CommandTemplateException UnterminatedValueName(string template, TemplateToken token) + { + return CommandLineTemplateExceptionFactory.Create( + template, token, + $"Encountered unterminated value name '{token.Value}'.", + "Unterminated value name."); + } + + internal static CommandTemplateException ArgumentCannotContainOptions(string template, TemplateToken token) + { + return CommandLineTemplateExceptionFactory.Create( + template, token, + "Arguments can not contain options.", + "Not permitted."); + } + + internal static CommandTemplateException MultipleValuesAreNotSupported(string template, TemplateToken token) + { + return CommandLineTemplateExceptionFactory.Create(template, token, + "Multiple values are not supported.", + "Too many values."); + } + + internal static CommandTemplateException ValuesMustHaveName(string template, TemplateToken token) + { + return CommandLineTemplateExceptionFactory.Create(template, token, + "Values without name are not allowed.", + "Missing value name."); + } + + internal static CommandTemplateException OptionsMustHaveName(string template, TemplateToken token) + { + return CommandLineTemplateExceptionFactory.Create(template, token, + "Options without name are not allowed.", + "Missing option name."); + } + + internal static CommandTemplateException OptionNamesCannotStartWithDigit(string template, TemplateToken token) + { + // Rewrite the token to point to the option name instead of the whole string. + token = new TemplateToken( + token.TokenKind, + token.TokenKind == TemplateToken.Kind.ShortName ? token.Position + 1 : token.Position + 2, + token.Value, token.Value); + + return CommandLineTemplateExceptionFactory.Create(template, token, + "Option names cannot start with a digit.", + "Invalid option name."); + } + + internal static CommandTemplateException InvalidCharacterInOptionName(string template, TemplateToken token, char character) + { + // Rewrite the token to point to the invalid character instead of the whole value. + var position = (token.TokenKind == TemplateToken.Kind.ShortName + ? token.Position + 1 + : token.Position + 2) + token.Value.OrdinalIndexOf(character); + + token = new TemplateToken( + token.TokenKind, position, + token.Value, character.ToString(CultureInfo.InvariantCulture)); + + return CommandLineTemplateExceptionFactory.Create(template, token, + $"Encountered invalid character '{character}' in option name.", + "Invalid character."); + } + + internal static CommandTemplateException LongOptionMustHaveMoreThanOneCharacter(string template, TemplateToken token) + { + // Rewrite the token to point to the option name instead of the whole option. + token = new TemplateToken(token.TokenKind, token.Position + 2, token.Value, token.Value); + + return CommandLineTemplateExceptionFactory.Create(template, token, + "Long option names must consist of more than one character.", + "Invalid option name."); + } + + internal static CommandTemplateException MultipleShortOptionNamesNotAllowed(string template, TemplateToken token) + { + return CommandLineTemplateExceptionFactory.Create(template, token, + "Multiple short option names are not supported.", + "Too many short options."); + } + + internal static CommandTemplateException ShortOptionMustOnlyBeOneCharacter(string template, TemplateToken token) + { + // Rewrite the token to point to the option name instead of the whole option. + token = new TemplateToken(token.TokenKind, token.Position + 1, token.Value, token.Value); + + return CommandLineTemplateExceptionFactory.Create(template, token, + "Short option names can not be longer than one character.", + "Invalid option name."); + } + + internal static CommandTemplateException MultipleOptionValuesAreNotSupported(string template, TemplateToken token) + { + return CommandLineTemplateExceptionFactory.Create(template, token, + "Multiple option values are not supported.", + "Too many option values."); + } + + internal static CommandTemplateException InvalidCharacterInValueName(string template, TemplateToken token, char character) + { + // Rewrite the token to point to the invalid character instead of the whole value. + token = new TemplateToken( + token.TokenKind, + token.Position + 1 + token.Value.OrdinalIndexOf(character), + token.Value, character.ToString(CultureInfo.InvariantCulture)); + + return CommandLineTemplateExceptionFactory.Create(template, token, + $"Encountered invalid character '{character}' in value name.", + "Invalid character."); + } + + internal static CommandTemplateException MissingLongAndShortName(string template, TemplateToken? token) + { + return CommandLineTemplateExceptionFactory.Create(template, token, + "No long or short name for option has been specified.", + "Missing option. Was this meant to be an argument?"); + } + + internal static CommandTemplateException ArgumentsMustHaveValueName(string template) + { + return CommandLineTemplateExceptionFactory.Create(template, null, + "Arguments must have a value name.", + "Missing value name."); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/ConfiguratorExtensions.cs b/src/Spectre.Console/Cli/ConfiguratorExtensions.cs index 853ac60..789c55b 100644 --- a/src/Spectre.Console/Cli/ConfiguratorExtensions.cs +++ b/src/Spectre.Console/Cli/ConfiguratorExtensions.cs @@ -1,262 +1,261 @@ using System; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// Contains extensions for +/// and . +/// +public static class ConfiguratorExtensions { /// - /// Contains extensions for - /// and . + /// Sets the name of the application. /// - public static class ConfiguratorExtensions + /// The configurator. + /// The name of the application. + /// A configurator that can be used to configure the application further. + public static IConfigurator SetApplicationName(this IConfigurator configurator, string name) { - /// - /// Sets the name of the application. - /// - /// The configurator. - /// The name of the application. - /// A configurator that can be used to configure the application further. - public static IConfigurator SetApplicationName(this IConfigurator configurator, string name) + if (configurator == null) { - if (configurator == null) - { - throw new ArgumentNullException(nameof(configurator)); - } - - configurator.Settings.ApplicationName = name; - return configurator; + throw new ArgumentNullException(nameof(configurator)); } - /// - /// Overrides the auto-detected version of the application. - /// - /// The configurator. - /// The version of application. - /// A configurator that can be used to configure the application further. - public static IConfigurator SetApplicationVersion(this IConfigurator configurator, string version) - { - if (configurator == null) - { - throw new ArgumentNullException(nameof(configurator)); - } - - configurator.Settings.ApplicationVersion = version; - return configurator; - } - - /// - /// Configures the console. - /// - /// The configurator. - /// The console. - /// A configurator that can be used to configure the application further. - public static IConfigurator ConfigureConsole(this IConfigurator configurator, IAnsiConsole console) - { - if (configurator == null) - { - throw new ArgumentNullException(nameof(configurator)); - } - - configurator.Settings.Console = console; - return configurator; - } - - /// - /// Sets the parsing mode to strict. - /// - /// The configurator. - /// A configurator that can be used to configure the application further. - public static IConfigurator UseStrictParsing(this IConfigurator configurator) - { - if (configurator == null) - { - throw new ArgumentNullException(nameof(configurator)); - } - - configurator.Settings.StrictParsing = true; - return configurator; - } - - /// - /// Tells the command line application to propagate all - /// exceptions to the user. - /// - /// The configurator. - /// A configurator that can be used to configure the application further. - public static IConfigurator PropagateExceptions(this IConfigurator configurator) - { - if (configurator == null) - { - throw new ArgumentNullException(nameof(configurator)); - } - - configurator.Settings.PropagateExceptions = true; - return configurator; - } - - /// - /// Configures case sensitivity. - /// - /// The configuration. - /// The case sensitivity. - /// A configurator that can be used to configure the application further. - public static IConfigurator CaseSensitivity(this IConfigurator configurator, CaseSensitivity sensitivity) - { - if (configurator == null) - { - throw new ArgumentNullException(nameof(configurator)); - } - - configurator.Settings.CaseSensitivity = sensitivity; - return configurator; - } - - /// - /// Tells the command line application to validate all - /// examples before running the application. - /// - /// The configurator. - /// A configurator that can be used to configure the application further. - public static IConfigurator ValidateExamples(this IConfigurator configurator) - { - if (configurator == null) - { - throw new ArgumentNullException(nameof(configurator)); - } - - configurator.Settings.ValidateExamples = true; - return configurator; - } - - /// - /// Sets the command interceptor to be used. - /// - /// The configurator. - /// A . - /// A configurator that can be used to configure the application further. - public static IConfigurator SetInterceptor(this IConfigurator configurator, ICommandInterceptor interceptor) - { - if (configurator == null) - { - throw new ArgumentNullException(nameof(configurator)); - } - - configurator.Settings.Interceptor = interceptor; - return configurator; - } - - /// - /// Adds a command branch. - /// - /// The configurator. - /// The name of the command branch. - /// The command branch configuration. - public static void AddBranch( - this IConfigurator configurator, - string name, - Action> action) - { - if (configurator == null) - { - throw new ArgumentNullException(nameof(configurator)); - } - - configurator.AddBranch(name, action); - } - - /// - /// Adds a command branch. - /// - /// The command setting type. - /// The configurator. - /// The name of the command branch. - /// The command branch configuration. - public static void AddBranch( - this IConfigurator configurator, - string name, - Action> action) - where TSettings : CommandSettings - { - if (configurator == null) - { - throw new ArgumentNullException(nameof(configurator)); - } - - configurator.AddBranch(name, action); - } - - /// - /// Adds a command without settings that executes a delegate. - /// - /// The configurator. - /// The name of the command. - /// The delegate to execute as part of command execution. - /// A command configurator that can be used to configure the command further. - public static ICommandConfigurator AddDelegate( - this IConfigurator configurator, - string name, - Func func) - { - if (configurator == null) - { - throw new ArgumentNullException(nameof(configurator)); - } - - return configurator.AddDelegate(name, (c, _) => func(c)); - } - - /// - /// Adds a command without settings that executes a delegate. - /// - /// The command setting type. - /// The configurator. - /// The name of the command. - /// The delegate to execute as part of command execution. - /// A command configurator that can be used to configure the command further. - public static ICommandConfigurator AddDelegate( - this IConfigurator configurator, - string name, - Func func) - where TSettings : CommandSettings - { - if (configurator == null) - { - throw new ArgumentNullException(nameof(configurator)); - } - - return configurator.AddDelegate(name, (c, _) => func(c)); - } - - /// - /// Sets the ExceptionsHandler. - /// Setting this way will use the - /// default exit code of -1. - /// - /// The configurator. - /// The Action that handles the exception. - /// A configurator that can be used to configure the application further. - public static IConfigurator SetExceptionHandler(this IConfigurator configurator, Action exceptionHandler) - { - return configurator.SetExceptionHandler(ex => - { - exceptionHandler(ex); - return -1; - }); - } - - /// - /// Sets the ExceptionsHandler. - /// - /// The configurator. - /// The Action that handles the exception. - /// A configurator that can be used to configure the application further. - public static IConfigurator SetExceptionHandler(this IConfigurator configurator, Func? exceptionHandler) - { - if (configurator == null) - { - throw new ArgumentNullException(nameof(configurator)); - } - - configurator.Settings.ExceptionHandler = exceptionHandler; - return configurator; - } + configurator.Settings.ApplicationName = name; + return configurator; } -} + + /// + /// Overrides the auto-detected version of the application. + /// + /// The configurator. + /// The version of application. + /// A configurator that can be used to configure the application further. + public static IConfigurator SetApplicationVersion(this IConfigurator configurator, string version) + { + if (configurator == null) + { + throw new ArgumentNullException(nameof(configurator)); + } + + configurator.Settings.ApplicationVersion = version; + return configurator; + } + + /// + /// Configures the console. + /// + /// The configurator. + /// The console. + /// A configurator that can be used to configure the application further. + public static IConfigurator ConfigureConsole(this IConfigurator configurator, IAnsiConsole console) + { + if (configurator == null) + { + throw new ArgumentNullException(nameof(configurator)); + } + + configurator.Settings.Console = console; + return configurator; + } + + /// + /// Sets the parsing mode to strict. + /// + /// The configurator. + /// A configurator that can be used to configure the application further. + public static IConfigurator UseStrictParsing(this IConfigurator configurator) + { + if (configurator == null) + { + throw new ArgumentNullException(nameof(configurator)); + } + + configurator.Settings.StrictParsing = true; + return configurator; + } + + /// + /// Tells the command line application to propagate all + /// exceptions to the user. + /// + /// The configurator. + /// A configurator that can be used to configure the application further. + public static IConfigurator PropagateExceptions(this IConfigurator configurator) + { + if (configurator == null) + { + throw new ArgumentNullException(nameof(configurator)); + } + + configurator.Settings.PropagateExceptions = true; + return configurator; + } + + /// + /// Configures case sensitivity. + /// + /// The configuration. + /// The case sensitivity. + /// A configurator that can be used to configure the application further. + public static IConfigurator CaseSensitivity(this IConfigurator configurator, CaseSensitivity sensitivity) + { + if (configurator == null) + { + throw new ArgumentNullException(nameof(configurator)); + } + + configurator.Settings.CaseSensitivity = sensitivity; + return configurator; + } + + /// + /// Tells the command line application to validate all + /// examples before running the application. + /// + /// The configurator. + /// A configurator that can be used to configure the application further. + public static IConfigurator ValidateExamples(this IConfigurator configurator) + { + if (configurator == null) + { + throw new ArgumentNullException(nameof(configurator)); + } + + configurator.Settings.ValidateExamples = true; + return configurator; + } + + /// + /// Sets the command interceptor to be used. + /// + /// The configurator. + /// A . + /// A configurator that can be used to configure the application further. + public static IConfigurator SetInterceptor(this IConfigurator configurator, ICommandInterceptor interceptor) + { + if (configurator == null) + { + throw new ArgumentNullException(nameof(configurator)); + } + + configurator.Settings.Interceptor = interceptor; + return configurator; + } + + /// + /// Adds a command branch. + /// + /// The configurator. + /// The name of the command branch. + /// The command branch configuration. + public static void AddBranch( + this IConfigurator configurator, + string name, + Action> action) + { + if (configurator == null) + { + throw new ArgumentNullException(nameof(configurator)); + } + + configurator.AddBranch(name, action); + } + + /// + /// Adds a command branch. + /// + /// The command setting type. + /// The configurator. + /// The name of the command branch. + /// The command branch configuration. + public static void AddBranch( + this IConfigurator configurator, + string name, + Action> action) + where TSettings : CommandSettings + { + if (configurator == null) + { + throw new ArgumentNullException(nameof(configurator)); + } + + configurator.AddBranch(name, action); + } + + /// + /// Adds a command without settings that executes a delegate. + /// + /// The configurator. + /// The name of the command. + /// The delegate to execute as part of command execution. + /// A command configurator that can be used to configure the command further. + public static ICommandConfigurator AddDelegate( + this IConfigurator configurator, + string name, + Func func) + { + if (configurator == null) + { + throw new ArgumentNullException(nameof(configurator)); + } + + return configurator.AddDelegate(name, (c, _) => func(c)); + } + + /// + /// Adds a command without settings that executes a delegate. + /// + /// The command setting type. + /// The configurator. + /// The name of the command. + /// The delegate to execute as part of command execution. + /// A command configurator that can be used to configure the command further. + public static ICommandConfigurator AddDelegate( + this IConfigurator configurator, + string name, + Func func) + where TSettings : CommandSettings + { + if (configurator == null) + { + throw new ArgumentNullException(nameof(configurator)); + } + + return configurator.AddDelegate(name, (c, _) => func(c)); + } + + /// + /// Sets the ExceptionsHandler. + /// Setting this way will use the + /// default exit code of -1. + /// + /// The configurator. + /// The Action that handles the exception. + /// A configurator that can be used to configure the application further. + public static IConfigurator SetExceptionHandler(this IConfigurator configurator, Action exceptionHandler) + { + return configurator.SetExceptionHandler(ex => + { + exceptionHandler(ex); + return -1; + }); + } + + /// + /// Sets the ExceptionsHandler. + /// + /// The configurator. + /// The Action that handles the exception. + /// A configurator that can be used to configure the application further. + public static IConfigurator SetExceptionHandler(this IConfigurator configurator, Func? exceptionHandler) + { + if (configurator == null) + { + throw new ArgumentNullException(nameof(configurator)); + } + + configurator.Settings.ExceptionHandler = exceptionHandler; + return configurator; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/EmptyCommandSettings.cs b/src/Spectre.Console/Cli/EmptyCommandSettings.cs index 8e1cb4b..7246c3f 100644 --- a/src/Spectre.Console/Cli/EmptyCommandSettings.cs +++ b/src/Spectre.Console/Cli/EmptyCommandSettings.cs @@ -1,9 +1,8 @@ -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// Represents empty settings. +/// +public sealed class EmptyCommandSettings : CommandSettings { - /// - /// Represents empty settings. - /// - public sealed class EmptyCommandSettings : CommandSettings - { - } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/FlagValue.cs b/src/Spectre.Console/Cli/FlagValue.cs index 9ae8845..2d697f8 100644 --- a/src/Spectre.Console/Cli/FlagValue.cs +++ b/src/Spectre.Console/Cli/FlagValue.cs @@ -1,59 +1,58 @@ using System; using System.Globalization; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// Implementation of a flag with an optional value. +/// +/// The flag's element type. +public sealed class FlagValue : IFlagValue { /// - /// Implementation of a flag with an optional value. + /// Gets or sets a value indicating whether or not the flag was set or not. /// - /// The flag's element type. - public sealed class FlagValue : IFlagValue - { - /// - /// Gets or sets a value indicating whether or not the flag was set or not. - /// - public bool IsSet { get; set; } + public bool IsSet { get; set; } #pragma warning disable CS8618 // Non-nullable field is uninitialized. Consider declaring as nullable. - /// - /// Gets or sets the flag's value. - /// - public T Value { get; set; } + /// + /// Gets or sets the flag's value. + /// + public T Value { get; set; } #pragma warning restore CS8618 // Non-nullable field is uninitialized. Consider declaring as nullable. - /// - Type IFlagValue.Type => typeof(T); + /// + Type IFlagValue.Type => typeof(T); - /// - object? IFlagValue.Value + /// + object? IFlagValue.Value + { + get => Value; + set { - get => Value; - set - { #pragma warning disable CS8601 // Possible null reference assignment. #pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. - Value = (T)value; + Value = (T)value; #pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type. #pragma warning restore CS8601 // Possible null reference assignment. - } - } - - /// - public override string ToString() - { - var flag = (IFlagValue)this; - if (flag.Value != null) - { - return string.Format( - CultureInfo.InvariantCulture, - "Set={0}, Value={1}", - IsSet, - flag.Value.ToString()); - } - - return string.Format( - CultureInfo.InvariantCulture, - "Set={0}", IsSet); } } -} + + /// + public override string ToString() + { + var flag = (IFlagValue)this; + if (flag.Value != null) + { + return string.Format( + CultureInfo.InvariantCulture, + "Set={0}, Value={1}", + IsSet, + flag.Value.ToString()); + } + + return string.Format( + CultureInfo.InvariantCulture, + "Set={0}", IsSet); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/ICommand.cs b/src/Spectre.Console/Cli/ICommand.cs index b494ab2..3c8c9bf 100644 --- a/src/Spectre.Console/Cli/ICommand.cs +++ b/src/Spectre.Console/Cli/ICommand.cs @@ -1,26 +1,25 @@ using System.Threading.Tasks; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// Represents a command. +/// +public interface ICommand { /// - /// Represents a command. + /// Validates the specified settings and remaining arguments. /// - public interface ICommand - { - /// - /// Validates the specified settings and remaining arguments. - /// - /// The command context. - /// The settings. - /// The validation result. - ValidationResult Validate(CommandContext context, CommandSettings settings); + /// The command context. + /// The settings. + /// The validation result. + ValidationResult Validate(CommandContext context, CommandSettings settings); - /// - /// Executes the command. - /// - /// The command context. - /// The settings. - /// The validation result. - Task Execute(CommandContext context, CommandSettings settings); - } + /// + /// Executes the command. + /// + /// The command context. + /// The settings. + /// The validation result. + Task Execute(CommandContext context, CommandSettings settings); } \ No newline at end of file diff --git a/src/Spectre.Console/Cli/ICommandApp.cs b/src/Spectre.Console/Cli/ICommandApp.cs index faed0cd..005e810 100644 --- a/src/Spectre.Console/Cli/ICommandApp.cs +++ b/src/Spectre.Console/Cli/ICommandApp.cs @@ -2,31 +2,30 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// Represents a command line application. +/// +public interface ICommandApp { /// - /// Represents a command line application. + /// Configures the command line application. /// - public interface ICommandApp - { - /// - /// Configures the command line application. - /// - /// The configuration. - void Configure(Action configuration); + /// The configuration. + void Configure(Action configuration); - /// - /// Runs the command line application with specified arguments. - /// - /// The arguments. - /// The exit code from the executed command. - int Run(IEnumerable args); + /// + /// Runs the command line application with specified arguments. + /// + /// The arguments. + /// The exit code from the executed command. + int Run(IEnumerable args); - /// - /// Runs the command line application with specified arguments. - /// - /// The arguments. - /// The exit code from the executed command. - Task RunAsync(IEnumerable args); - } + /// + /// Runs the command line application with specified arguments. + /// + /// The arguments. + /// The exit code from the executed command. + Task RunAsync(IEnumerable args); } \ No newline at end of file diff --git a/src/Spectre.Console/Cli/ICommandAppSettings.cs b/src/Spectre.Console/Cli/ICommandAppSettings.cs index 20580e9..6768919 100644 --- a/src/Spectre.Console/Cli/ICommandAppSettings.cs +++ b/src/Spectre.Console/Cli/ICommandAppSettings.cs @@ -1,64 +1,63 @@ using System; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// Represents a command line application settings. +/// +public interface ICommandAppSettings { /// - /// Represents a command line application settings. + /// Gets or sets the application name. /// - public interface ICommandAppSettings - { - /// - /// Gets or sets the application name. - /// - string? ApplicationName { get; set; } + string? ApplicationName { get; set; } - /// - /// Gets or sets the application version (use it to override auto-detected value). - /// - string? ApplicationVersion { get; set; } + /// + /// Gets or sets the application version (use it to override auto-detected value). + /// + string? ApplicationVersion { get; set; } - /// - /// Gets or sets the . - /// - IAnsiConsole? Console { get; set; } + /// + /// Gets or sets the . + /// + IAnsiConsole? Console { get; set; } - /// - /// Gets or sets the used - /// to intercept settings before it's being sent to the command. - /// - ICommandInterceptor? Interceptor { get; set; } + /// + /// Gets or sets the used + /// to intercept settings before it's being sent to the command. + /// + ICommandInterceptor? Interceptor { get; set; } - /// - /// Gets the type registrar. - /// - ITypeRegistrarFrontend Registrar { get; } + /// + /// Gets the type registrar. + /// + ITypeRegistrarFrontend Registrar { get; } - /// - /// Gets or sets case sensitivity. - /// - CaseSensitivity CaseSensitivity { get; set; } + /// + /// Gets or sets case sensitivity. + /// + CaseSensitivity CaseSensitivity { get; set; } - /// - /// Gets or sets a value indicating whether or not parsing is strict. - /// - bool StrictParsing { get; set; } + /// + /// Gets or sets a value indicating whether or not parsing is strict. + /// + bool StrictParsing { get; set; } - /// - /// Gets or sets a value indicating whether or not exceptions should be propagated. - /// Setting this to true will disable default Exception handling and - /// any , if set. - /// - bool PropagateExceptions { get; set; } + /// + /// Gets or sets a value indicating whether or not exceptions should be propagated. + /// Setting this to true will disable default Exception handling and + /// any , if set. + /// + bool PropagateExceptions { get; set; } - /// - /// Gets or sets a value indicating whether or not examples should be validated. - /// - bool ValidateExamples { get; set; } + /// + /// Gets or sets a value indicating whether or not examples should be validated. + /// + bool ValidateExamples { get; set; } - /// - /// Gets or sets a handler for Exceptions. - /// This handler will not be called, if is set to true. - /// - public Func? ExceptionHandler { get; set; } - } + /// + /// Gets or sets a handler for Exceptions. + /// This handler will not be called, if is set to true. + /// + public Func? ExceptionHandler { get; set; } } \ No newline at end of file diff --git a/src/Spectre.Console/Cli/ICommandConfigurator.cs b/src/Spectre.Console/Cli/ICommandConfigurator.cs index 22dcccd..2abf311 100644 --- a/src/Spectre.Console/Cli/ICommandConfigurator.cs +++ b/src/Spectre.Console/Cli/ICommandConfigurator.cs @@ -1,44 +1,43 @@ -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// Represents a command configurator. +/// +public interface ICommandConfigurator { /// - /// Represents a command configurator. + /// Adds an example of how to use the command. /// - public interface ICommandConfigurator - { - /// - /// Adds an example of how to use the command. - /// - /// The example arguments. - /// The same instance so that multiple calls can be chained. - ICommandConfigurator WithExample(string[] args); + /// The example arguments. + /// The same instance so that multiple calls can be chained. + ICommandConfigurator WithExample(string[] args); - /// - /// Adds an alias (an alternative name) to the command being configured. - /// - /// The alias to add to the command being configured. - /// The same instance so that multiple calls can be chained. - ICommandConfigurator WithAlias(string name); + /// + /// Adds an alias (an alternative name) to the command being configured. + /// + /// The alias to add to the command being configured. + /// The same instance so that multiple calls can be chained. + ICommandConfigurator WithAlias(string name); - /// - /// Sets the description of the command. - /// - /// The command description. - /// The same instance so that multiple calls can be chained. - ICommandConfigurator WithDescription(string description); + /// + /// Sets the description of the command. + /// + /// The command description. + /// The same instance so that multiple calls can be chained. + ICommandConfigurator WithDescription(string description); - /// - /// Sets data that will be passed to the command via the . - /// - /// The data to pass to the command. - /// The same instance so that multiple calls can be chained. - ICommandConfigurator WithData(object data); + /// + /// Sets data that will be passed to the command via the . + /// + /// The data to pass to the command. + /// The same instance so that multiple calls can be chained. + ICommandConfigurator WithData(object data); - /// - /// Marks the command as hidden. - /// Hidden commands do not show up in help documentation or - /// generated XML models. - /// - /// The same instance so that multiple calls can be chained. - ICommandConfigurator IsHidden(); - } + /// + /// Marks the command as hidden. + /// Hidden commands do not show up in help documentation or + /// generated XML models. + /// + /// The same instance so that multiple calls can be chained. + ICommandConfigurator IsHidden(); } \ No newline at end of file diff --git a/src/Spectre.Console/Cli/ICommandInterceptor.cs b/src/Spectre.Console/Cli/ICommandInterceptor.cs index 3b1888f..7854c2f 100644 --- a/src/Spectre.Console/Cli/ICommandInterceptor.cs +++ b/src/Spectre.Console/Cli/ICommandInterceptor.cs @@ -1,17 +1,16 @@ -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// Represents a command settings interceptor that +/// will intercept command settings before it's +/// passed to a command. +/// +public interface ICommandInterceptor { /// - /// Represents a command settings interceptor that - /// will intercept command settings before it's - /// passed to a command. + /// Intercepts command information before it's passed to a command. /// - public interface ICommandInterceptor - { - /// - /// Intercepts command information before it's passed to a command. - /// - /// The intercepted . - /// The intercepted . - void Intercept(CommandContext context, CommandSettings settings); - } -} + /// The intercepted . + /// The intercepted . + void Intercept(CommandContext context, CommandSettings settings); +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/ICommandLimiterOfT.cs b/src/Spectre.Console/Cli/ICommandLimiterOfT.cs index 45ad077..5291b6f 100644 --- a/src/Spectre.Console/Cli/ICommandLimiterOfT.cs +++ b/src/Spectre.Console/Cli/ICommandLimiterOfT.cs @@ -1,12 +1,11 @@ -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// Represents a command limiter. +/// +/// The type of the settings to limit to. +/// +public interface ICommandLimiter : ICommand + where TSettings : CommandSettings { - /// - /// Represents a command limiter. - /// - /// The type of the settings to limit to. - /// - public interface ICommandLimiter : ICommand - where TSettings : CommandSettings - { - } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/ICommandOfT.cs b/src/Spectre.Console/Cli/ICommandOfT.cs index a6878b3..a563372 100644 --- a/src/Spectre.Console/Cli/ICommandOfT.cs +++ b/src/Spectre.Console/Cli/ICommandOfT.cs @@ -1,20 +1,19 @@ using System.Threading.Tasks; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// Represents a command. +/// +/// The settings type. +public interface ICommand : ICommandLimiter + where TSettings : CommandSettings { /// - /// Represents a command. + /// Executes the command. /// - /// The settings type. - public interface ICommand : ICommandLimiter - where TSettings : CommandSettings - { - /// - /// Executes the command. - /// - /// The command context. - /// The settings. - /// An integer indicating whether or not the command executed successfully. - Task Execute(CommandContext context, TSettings settings); - } -} + /// The command context. + /// The settings. + /// An integer indicating whether or not the command executed successfully. + Task Execute(CommandContext context, TSettings settings); +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/ICommandParameterInfo.cs b/src/Spectre.Console/Cli/ICommandParameterInfo.cs index ff3cd9c..4121115 100644 --- a/src/Spectre.Console/Cli/ICommandParameterInfo.cs +++ b/src/Spectre.Console/Cli/ICommandParameterInfo.cs @@ -1,27 +1,26 @@ using System; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// Represents a command parameter. +/// +public interface ICommandParameterInfo { /// - /// Represents a command parameter. + /// Gets the property name. /// - public interface ICommandParameterInfo - { - /// - /// Gets the property name. - /// - /// The property name. - public string PropertyName { get; } + /// The property name. + public string PropertyName { get; } - /// - /// Gets the parameter type. - /// - public Type ParameterType { get; } + /// + /// Gets the parameter type. + /// + public Type ParameterType { get; } - /// - /// Gets the description. - /// - /// The description. - public string? Description { get; } - } + /// + /// Gets the description. + /// + /// The description. + public string? Description { get; } } \ No newline at end of file diff --git a/src/Spectre.Console/Cli/IConfigurator.cs b/src/Spectre.Console/Cli/IConfigurator.cs index 270c54c..14b27f1 100644 --- a/src/Spectre.Console/Cli/IConfigurator.cs +++ b/src/Spectre.Console/Cli/IConfigurator.cs @@ -1,49 +1,48 @@ using System; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// Represents a configurator. +/// +public interface IConfigurator { /// - /// Represents a configurator. + /// Gets the command app settings. /// - public interface IConfigurator - { - /// - /// Gets the command app settings. - /// - public ICommandAppSettings Settings { get; } + public ICommandAppSettings Settings { get; } - /// - /// Adds an example of how to use the application. - /// - /// The example arguments. - void AddExample(string[] args); + /// + /// Adds an example of how to use the application. + /// + /// The example arguments. + void AddExample(string[] args); - /// - /// Adds a command. - /// - /// The command type. - /// The name of the command. - /// A command configurator that can be used to configure the command further. - ICommandConfigurator AddCommand(string name) - where TCommand : class, ICommand; + /// + /// Adds a command. + /// + /// The command type. + /// The name of the command. + /// A command configurator that can be used to configure the command further. + ICommandConfigurator AddCommand(string name) + where TCommand : class, ICommand; - /// - /// Adds a command that executes a delegate. - /// - /// The command setting type. - /// The name of the command. - /// The delegate to execute as part of command execution. - /// A command configurator that can be used to configure the command further. - ICommandConfigurator AddDelegate(string name, Func func) - where TSettings : CommandSettings; + /// + /// Adds a command that executes a delegate. + /// + /// The command setting type. + /// The name of the command. + /// The delegate to execute as part of command execution. + /// A command configurator that can be used to configure the command further. + ICommandConfigurator AddDelegate(string name, Func func) + where TSettings : CommandSettings; - /// - /// Adds a command branch. - /// - /// The command setting type. - /// The name of the command branch. - /// The command branch configurator. - void AddBranch(string name, Action> action) - where TSettings : CommandSettings; - } + /// + /// Adds a command branch. + /// + /// The command setting type. + /// The name of the command branch. + /// The command branch configurator. + void AddBranch(string name, Action> action) + where TSettings : CommandSettings; } \ No newline at end of file diff --git a/src/Spectre.Console/Cli/IConfiguratorOfT.cs b/src/Spectre.Console/Cli/IConfiguratorOfT.cs index 198b575..1bcfcb6 100644 --- a/src/Spectre.Console/Cli/IConfiguratorOfT.cs +++ b/src/Spectre.Console/Cli/IConfiguratorOfT.cs @@ -1,59 +1,58 @@ using System; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// Represents a configurator for specific settings. +/// +/// The command setting type. +public interface IConfigurator + where TSettings : CommandSettings { /// - /// Represents a configurator for specific settings. + /// Sets the description of the branch. /// - /// The command setting type. - public interface IConfigurator - where TSettings : CommandSettings - { - /// - /// Sets the description of the branch. - /// - /// The description of the branch. - void SetDescription(string description); + /// The description of the branch. + void SetDescription(string description); - /// - /// Adds an example of how to use the branch. - /// - /// The example arguments. - void AddExample(string[] args); + /// + /// Adds an example of how to use the branch. + /// + /// The example arguments. + void AddExample(string[] args); - /// - /// Marks the branch as hidden. - /// Hidden branches do not show up in help documentation or - /// generated XML models. - /// - void HideBranch(); + /// + /// Marks the branch as hidden. + /// Hidden branches do not show up in help documentation or + /// generated XML models. + /// + void HideBranch(); - /// - /// Adds a command. - /// - /// The command type. - /// The name of the command. - /// A command configurator that can be used to configure the command further. - ICommandConfigurator AddCommand(string name) - where TCommand : class, ICommandLimiter; + /// + /// Adds a command. + /// + /// The command type. + /// The name of the command. + /// A command configurator that can be used to configure the command further. + ICommandConfigurator AddCommand(string name) + where TCommand : class, ICommandLimiter; - /// - /// Adds a command that executes a delegate. - /// - /// The derived command setting type. - /// The name of the command. - /// The delegate to execute as part of command execution. - /// A command configurator that can be used to configure the command further. - ICommandConfigurator AddDelegate(string name, Func func) - where TDerivedSettings : TSettings; + /// + /// Adds a command that executes a delegate. + /// + /// The derived command setting type. + /// The name of the command. + /// The delegate to execute as part of command execution. + /// A command configurator that can be used to configure the command further. + ICommandConfigurator AddDelegate(string name, Func func) + where TDerivedSettings : TSettings; - /// - /// Adds a command branch. - /// - /// The derived command setting type. - /// The name of the command branch. - /// The command branch configuration. - void AddBranch(string name, Action> action) - where TDerivedSettings : TSettings; - } -} + /// + /// Adds a command branch. + /// + /// The derived command setting type. + /// The name of the command branch. + /// The command branch configuration. + void AddBranch(string name, Action> action) + where TDerivedSettings : TSettings; +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/IFlagValue.cs b/src/Spectre.Console/Cli/IFlagValue.cs index a0c56e8..c67a3a6 100644 --- a/src/Spectre.Console/Cli/IFlagValue.cs +++ b/src/Spectre.Console/Cli/IFlagValue.cs @@ -1,25 +1,24 @@ using System; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// Represents a flag with an optional value. +/// +public interface IFlagValue { /// - /// Represents a flag with an optional value. + /// Gets or sets a value indicating whether or not the flag was set or not. /// - public interface IFlagValue - { - /// - /// Gets or sets a value indicating whether or not the flag was set or not. - /// - bool IsSet { get; set; } + bool IsSet { get; set; } - /// - /// Gets the flag's element type. - /// - Type Type { get; } + /// + /// Gets the flag's element type. + /// + Type Type { get; } - /// - /// Gets or sets the flag's value. - /// - object? Value { get; set; } - } -} + /// + /// Gets or sets the flag's value. + /// + object? Value { get; set; } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/IRemainingArguments.cs b/src/Spectre.Console/Cli/IRemainingArguments.cs index c13716a..22d3009 100644 --- a/src/Spectre.Console/Cli/IRemainingArguments.cs +++ b/src/Spectre.Console/Cli/IRemainingArguments.cs @@ -1,21 +1,20 @@ using System.Collections.Generic; using System.Linq; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// Represents the remaining arguments. +/// +public interface IRemainingArguments { /// - /// Represents the remaining arguments. + /// Gets the parsed remaining arguments. /// - public interface IRemainingArguments - { - /// - /// Gets the parsed remaining arguments. - /// - ILookup Parsed { get; } + ILookup Parsed { get; } - /// - /// Gets the raw, non-parsed remaining arguments. - /// - IReadOnlyList Raw { get; } - } -} + /// + /// Gets the raw, non-parsed remaining arguments. + /// + IReadOnlyList Raw { get; } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/ITypeRegistrar.cs b/src/Spectre.Console/Cli/ITypeRegistrar.cs index 83b73aa..48f2a3a 100644 --- a/src/Spectre.Console/Cli/ITypeRegistrar.cs +++ b/src/Spectre.Console/Cli/ITypeRegistrar.cs @@ -1,38 +1,37 @@ using System; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// Represents a type registrar. +/// +public interface ITypeRegistrar { /// - /// Represents a type registrar. + /// Registers the specified service. /// - public interface ITypeRegistrar - { - /// - /// Registers the specified service. - /// - /// The service. - /// The implementation. - void Register(Type service, Type implementation); + /// The service. + /// The implementation. + void Register(Type service, Type implementation); - /// - /// Registers the specified instance. - /// - /// The service. - /// The implementation. - void RegisterInstance(Type service, object implementation); + /// + /// Registers the specified instance. + /// + /// The service. + /// The implementation. + void RegisterInstance(Type service, object implementation); - /// - /// Registers the specified instance lazily. - /// - /// The service. - /// The factory that creates the implementation. - void RegisterLazy(Type service, Func factory); + /// + /// Registers the specified instance lazily. + /// + /// The service. + /// The factory that creates the implementation. + void RegisterLazy(Type service, Func factory); - /// - /// Builds the type resolver representing the registrations - /// specified in the current instance. - /// - /// A type resolver. - ITypeResolver Build(); - } -} + /// + /// Builds the type resolver representing the registrations + /// specified in the current instance. + /// + /// A type resolver. + ITypeResolver Build(); +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/ITypeRegistrarFrontend.cs b/src/Spectre.Console/Cli/ITypeRegistrarFrontend.cs index 41c8b71..dbe955e 100644 --- a/src/Spectre.Console/Cli/ITypeRegistrarFrontend.cs +++ b/src/Spectre.Console/Cli/ITypeRegistrarFrontend.cs @@ -1,32 +1,31 @@ -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// Represents a user friendly frontend for a . +/// +public interface ITypeRegistrarFrontend { /// - /// Represents a user friendly frontend for a . + /// Registers the type with the type registrar as a singleton. /// - public interface ITypeRegistrarFrontend - { - /// - /// Registers the type with the type registrar as a singleton. - /// - /// The exposed service type. - /// The implementing type. - void Register() - where TImplementation : TService; + /// The exposed service type. + /// The implementing type. + void Register() + where TImplementation : TService; - /// - /// Registers the specified instance with the type registrar as a singleton. - /// - /// The type of the instance. - /// The instance to register. - void RegisterInstance(TImplementation instance); + /// + /// Registers the specified instance with the type registrar as a singleton. + /// + /// The type of the instance. + /// The instance to register. + void RegisterInstance(TImplementation instance); - /// - /// Registers the specified instance with the type registrar as a singleton. - /// - /// The exposed service type. - /// implementing type. - /// The instance to register. - void RegisterInstance(TImplementation instance) - where TImplementation : TService; - } -} + /// + /// Registers the specified instance with the type registrar as a singleton. + /// + /// The exposed service type. + /// implementing type. + /// The instance to register. + void RegisterInstance(TImplementation instance) + where TImplementation : TService; +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/ITypeResolver.cs b/src/Spectre.Console/Cli/ITypeResolver.cs index 9d65a66..a75af93 100644 --- a/src/Spectre.Console/Cli/ITypeResolver.cs +++ b/src/Spectre.Console/Cli/ITypeResolver.cs @@ -1,17 +1,16 @@ using System; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// Represents a type resolver. +/// +public interface ITypeResolver { /// - /// Represents a type resolver. + /// Resolves an instance of the specified type. /// - public interface ITypeResolver - { - /// - /// Resolves an instance of the specified type. - /// - /// The type to resolve. - /// An instance of the specified type, or null if no registration for the specified type exists. - object? Resolve(Type? type); - } -} + /// The type to resolve. + /// An instance of the specified type, or null if no registration for the specified type exists. + object? Resolve(Type? type); +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Binding/CommandConstructorBinder.cs b/src/Spectre.Console/Cli/Internal/Binding/CommandConstructorBinder.cs index f2c473a..a3b6d69 100644 --- a/src/Spectre.Console/Cli/Internal/Binding/CommandConstructorBinder.cs +++ b/src/Spectre.Console/Cli/Internal/Binding/CommandConstructorBinder.cs @@ -2,54 +2,53 @@ using System; using System.Collections.Generic; using System.Reflection; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal static class CommandConstructorBinder { - internal static class CommandConstructorBinder + public static CommandSettings CreateSettings(CommandValueLookup lookup, ConstructorInfo constructor, ITypeResolver resolver) { - public static CommandSettings CreateSettings(CommandValueLookup lookup, ConstructorInfo constructor, ITypeResolver resolver) + if (constructor.DeclaringType == null) { - if (constructor.DeclaringType == null) - { - throw new InvalidOperationException("Cannot create settings since constructor have no declaring type."); - } - - var parameters = new List(); - var mapped = new HashSet(); - foreach (var parameter in constructor.GetParameters()) - { - if (lookup.TryGetParameterWithName(parameter.Name, out var result)) - { - parameters.Add(result.Value); - mapped.Add(result.Parameter.Id); - } - else - { - var value = resolver.Resolve(parameter.ParameterType); - if (value == null) - { - throw CommandRuntimeException.CouldNotResolveType(parameter.ParameterType); - } - - parameters.Add(value); - } - } - - // Create the settings. - if (!(Activator.CreateInstance(constructor.DeclaringType, parameters.ToArray()) is CommandSettings settings)) - { - throw new InvalidOperationException("Could not create settings"); - } - - // Try to do property injection for parameters that wasn't injected. - foreach (var (parameter, value) in lookup) - { - if (!mapped.Contains(parameter.Id) && parameter.Property.SetMethod != null) - { - parameter.Property.SetValue(settings, value); - } - } - - return settings; + throw new InvalidOperationException("Cannot create settings since constructor have no declaring type."); } + + var parameters = new List(); + var mapped = new HashSet(); + foreach (var parameter in constructor.GetParameters()) + { + if (lookup.TryGetParameterWithName(parameter.Name, out var result)) + { + parameters.Add(result.Value); + mapped.Add(result.Parameter.Id); + } + else + { + var value = resolver.Resolve(parameter.ParameterType); + if (value == null) + { + throw CommandRuntimeException.CouldNotResolveType(parameter.ParameterType); + } + + parameters.Add(value); + } + } + + // Create the settings. + if (!(Activator.CreateInstance(constructor.DeclaringType, parameters.ToArray()) is CommandSettings settings)) + { + throw new InvalidOperationException("Could not create settings"); + } + + // Try to do property injection for parameters that wasn't injected. + foreach (var (parameter, value) in lookup) + { + if (!mapped.Contains(parameter.Id) && parameter.Property.SetMethod != null) + { + parameter.Property.SetValue(settings, value); + } + } + + return settings; } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Binding/CommandPropertyBinder.cs b/src/Spectre.Console/Cli/Internal/Binding/CommandPropertyBinder.cs index ca96acf..0486685 100644 --- a/src/Spectre.Console/Cli/Internal/Binding/CommandPropertyBinder.cs +++ b/src/Spectre.Console/Cli/Internal/Binding/CommandPropertyBinder.cs @@ -1,44 +1,43 @@ using System; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal static class CommandPropertyBinder { - internal static class CommandPropertyBinder + public static CommandSettings CreateSettings(CommandValueLookup lookup, Type settingsType, ITypeResolver resolver) { - public static CommandSettings CreateSettings(CommandValueLookup lookup, Type settingsType, ITypeResolver resolver) + var settings = CreateSettings(resolver, settingsType); + + foreach (var (parameter, value) in lookup) { - var settings = CreateSettings(resolver, settingsType); - - foreach (var (parameter, value) in lookup) + if (value != default) { - if (value != default) - { - parameter.Property.SetValue(settings, value); - } + parameter.Property.SetValue(settings, value); } + } - // Validate the settings. - var validationResult = settings.Validate(); - if (!validationResult.Successful) - { - throw CommandRuntimeException.ValidationFailed(validationResult); - } + // Validate the settings. + var validationResult = settings.Validate(); + if (!validationResult.Successful) + { + throw CommandRuntimeException.ValidationFailed(validationResult); + } + return settings; + } + + private static CommandSettings CreateSettings(ITypeResolver resolver, Type settingsType) + { + if (resolver.Resolve(settingsType) is CommandSettings settings) + { return settings; } - private static CommandSettings CreateSettings(ITypeResolver resolver, Type settingsType) + if (Activator.CreateInstance(settingsType) is CommandSettings instance) { - if (resolver.Resolve(settingsType) is CommandSettings settings) - { - return settings; - } - - if (Activator.CreateInstance(settingsType) is CommandSettings instance) - { - return instance; - } - - throw CommandParseException.CouldNotCreateSettings(settingsType); + return instance; } + + throw CommandParseException.CouldNotCreateSettings(settingsType); } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Binding/CommandValueBinder.cs b/src/Spectre.Console/Cli/Internal/Binding/CommandValueBinder.cs index 38a206e..49968ef 100644 --- a/src/Spectre.Console/Cli/Internal/Binding/CommandValueBinder.cs +++ b/src/Spectre.Console/Cli/Internal/Binding/CommandValueBinder.cs @@ -1,118 +1,117 @@ using System; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal sealed class CommandValueBinder { - internal sealed class CommandValueBinder + private readonly CommandValueLookup _lookup; + + public CommandValueBinder(CommandValueLookup lookup) { - private readonly CommandValueLookup _lookup; + _lookup = lookup; + } - public CommandValueBinder(CommandValueLookup lookup) + public void Bind(CommandParameter parameter, ITypeResolver resolver, object? value) + { + if (parameter.ParameterKind == ParameterKind.Pair) { - _lookup = lookup; + value = GetLookup(parameter, resolver, value); + } + else if (parameter.ParameterKind == ParameterKind.Vector) + { + value = GetArray(parameter, value); + } + else if (parameter.ParameterKind == ParameterKind.FlagWithValue) + { + value = GetFlag(parameter, value); } - public void Bind(CommandParameter parameter, ITypeResolver resolver, object? value) + _lookup.SetValue(parameter, value); + } + + private object GetLookup(CommandParameter parameter, ITypeResolver resolver, object? value) + { + var genericTypes = parameter.Property.PropertyType.GetGenericArguments(); + + var multimap = (IMultiMap?)_lookup.GetValue(parameter); + if (multimap == null) { - if (parameter.ParameterKind == ParameterKind.Pair) - { - value = GetLookup(parameter, resolver, value); - } - else if (parameter.ParameterKind == ParameterKind.Vector) - { - value = GetArray(parameter, value); - } - else if (parameter.ParameterKind == ParameterKind.FlagWithValue) - { - value = GetFlag(parameter, value); - } - - _lookup.SetValue(parameter, value); - } - - private object GetLookup(CommandParameter parameter, ITypeResolver resolver, object? value) - { - var genericTypes = parameter.Property.PropertyType.GetGenericArguments(); - - var multimap = (IMultiMap?)_lookup.GetValue(parameter); + multimap = Activator.CreateInstance(typeof(MultiMap<,>).MakeGenericType(genericTypes[0], genericTypes[1])) as IMultiMap; if (multimap == null) { - multimap = Activator.CreateInstance(typeof(MultiMap<,>).MakeGenericType(genericTypes[0], genericTypes[1])) as IMultiMap; - if (multimap == null) - { - throw new InvalidOperationException("Could not create multimap"); - } + throw new InvalidOperationException("Could not create multimap"); } - - // Create deconstructor. - var deconstructorType = parameter.PairDeconstructor?.Type ?? typeof(DefaultPairDeconstructor); - if (!(resolver.Resolve(deconstructorType) is IPairDeconstructor deconstructor)) - { - if (!(Activator.CreateInstance(deconstructorType) is IPairDeconstructor activatedDeconstructor)) - { - throw new InvalidOperationException($"Could not create pair deconstructor."); - } - - deconstructor = activatedDeconstructor; - } - - // Deconstruct and add to multimap. - var pair = deconstructor.Deconstruct(resolver, genericTypes[0], genericTypes[1], value as string); - if (pair.Key != null) - { - multimap.Add(pair); - } - - return multimap; } - private object GetArray(CommandParameter parameter, object? value) + // Create deconstructor. + var deconstructorType = parameter.PairDeconstructor?.Type ?? typeof(DefaultPairDeconstructor); + if (!(resolver.Resolve(deconstructorType) is IPairDeconstructor deconstructor)) { - // Add a new item to the array - var array = (Array?)_lookup.GetValue(parameter); - Array newArray; - - var elementType = parameter.Property.PropertyType.GetElementType(); - if (elementType == null) + if (!(Activator.CreateInstance(deconstructorType) is IPairDeconstructor activatedDeconstructor)) { - throw new InvalidOperationException("Could not get property type."); + throw new InvalidOperationException($"Could not create pair deconstructor."); } - if (array == null) - { - newArray = Array.CreateInstance(elementType, 1); - } - else - { - newArray = Array.CreateInstance(elementType, array.Length + 1); - array.CopyTo(newArray, 0); - } - - newArray.SetValue(value, newArray.Length - 1); - return newArray; + deconstructor = activatedDeconstructor; } - private object GetFlag(CommandParameter parameter, object? value) + // Deconstruct and add to multimap. + var pair = deconstructor.Deconstruct(resolver, genericTypes[0], genericTypes[1], value as string); + if (pair.Key != null) { - var flagValue = (IFlagValue?)_lookup.GetValue(parameter); + multimap.Add(pair); + } + + return multimap; + } + + private object GetArray(CommandParameter parameter, object? value) + { + // Add a new item to the array + var array = (Array?)_lookup.GetValue(parameter); + Array newArray; + + var elementType = parameter.Property.PropertyType.GetElementType(); + if (elementType == null) + { + throw new InvalidOperationException("Could not get property type."); + } + + if (array == null) + { + newArray = Array.CreateInstance(elementType, 1); + } + else + { + newArray = Array.CreateInstance(elementType, array.Length + 1); + array.CopyTo(newArray, 0); + } + + newArray.SetValue(value, newArray.Length - 1); + return newArray; + } + + private object GetFlag(CommandParameter parameter, object? value) + { + var flagValue = (IFlagValue?)_lookup.GetValue(parameter); + if (flagValue == null) + { + flagValue = (IFlagValue?)Activator.CreateInstance(parameter.ParameterType); if (flagValue == null) { - flagValue = (IFlagValue?)Activator.CreateInstance(parameter.ParameterType); - if (flagValue == null) - { - throw new InvalidOperationException("Could not create flag value."); - } + throw new InvalidOperationException("Could not create flag value."); } - - if (value != null) - { - // Null means set, but not with a valid value. - flagValue.Value = value; - } - - // If the parameter was mapped, then it's set. - flagValue.IsSet = true; - - return flagValue; } + + if (value != null) + { + // Null means set, but not with a valid value. + flagValue.Value = value; + } + + // If the parameter was mapped, then it's set. + flagValue.IsSet = true; + + return flagValue; } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Binding/CommandValueLookup.cs b/src/Spectre.Console/Cli/Internal/Binding/CommandValueLookup.cs index 721ba09..b7f9845 100644 --- a/src/Spectre.Console/Cli/Internal/Binding/CommandValueLookup.cs +++ b/src/Spectre.Console/Cli/Internal/Binding/CommandValueLookup.cs @@ -3,61 +3,60 @@ using System.Collections; using System.Collections.Generic; using System.Linq; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal sealed class CommandValueLookup : IEnumerable<(CommandParameter Parameter, object? Value)> { - internal sealed class CommandValueLookup : IEnumerable<(CommandParameter Parameter, object? Value)> + private readonly Dictionary _lookup; + + public CommandValueLookup() { - private readonly Dictionary _lookup; + _lookup = new Dictionary(); + } - public CommandValueLookup() + public IEnumerator<(CommandParameter Parameter, object? Value)> GetEnumerator() + { + foreach (var pair in _lookup) { - _lookup = new Dictionary(); + yield return pair.Value; } + } - public IEnumerator<(CommandParameter Parameter, object? Value)> GetEnumerator() + public bool HasParameterWithName(string? name) + { + if (name == null) { - foreach (var pair in _lookup) - { - yield return pair.Value; - } - } - - public bool HasParameterWithName(string? name) - { - if (name == null) - { - return false; - } - - return _lookup.Values.Any(pair => pair.Parameter.PropertyName.Equals(name, StringComparison.OrdinalIgnoreCase)); - } - - public bool TryGetParameterWithName(string? name, out (CommandParameter Parameter, object? Value) result) - { - if (HasParameterWithName(name)) - { - result = _lookup.Values.FirstOrDefault(pair => pair.Parameter.PropertyName.Equals(name, StringComparison.OrdinalIgnoreCase)); - return true; - } - - result = default; return false; } - public object? GetValue(CommandParameter parameter) - { - _lookup.TryGetValue(parameter.Id, out var result); - return result.Value; - } - - public void SetValue(CommandParameter parameter, object? value) - { - _lookup[parameter.Id] = (parameter, value); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } + return _lookup.Values.Any(pair => pair.Parameter.PropertyName.Equals(name, StringComparison.OrdinalIgnoreCase)); } -} + + public bool TryGetParameterWithName(string? name, out (CommandParameter Parameter, object? Value) result) + { + if (HasParameterWithName(name)) + { + result = _lookup.Values.FirstOrDefault(pair => pair.Parameter.PropertyName.Equals(name, StringComparison.OrdinalIgnoreCase)); + return true; + } + + result = default; + return false; + } + + public object? GetValue(CommandParameter parameter) + { + _lookup.TryGetValue(parameter.Id, out var result); + return result.Value; + } + + public void SetValue(CommandParameter parameter, object? value) + { + _lookup[parameter.Id] = (parameter, value); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Binding/CommandValueResolver.cs b/src/Spectre.Console/Cli/Internal/Binding/CommandValueResolver.cs index e190752..859c5f1 100644 --- a/src/Spectre.Console/Cli/Internal/Binding/CommandValueResolver.cs +++ b/src/Spectre.Console/Cli/Internal/Binding/CommandValueResolver.cs @@ -2,166 +2,165 @@ using System; using System.ComponentModel; using System.Diagnostics.CodeAnalysis; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal static class CommandValueResolver { - internal static class CommandValueResolver + public static CommandValueLookup GetParameterValues(CommandTree? tree, ITypeResolver resolver) { - public static CommandValueLookup GetParameterValues(CommandTree? tree, ITypeResolver resolver) + var lookup = new CommandValueLookup(); + var binder = new CommandValueBinder(lookup); + + CommandValidator.ValidateRequiredParameters(tree); + + while (tree != null) { - var lookup = new CommandValueLookup(); - var binder = new CommandValueBinder(lookup); - - CommandValidator.ValidateRequiredParameters(tree); - - while (tree != null) + // Process unmapped parameters. + foreach (var parameter in tree.Unmapped) { - // Process unmapped parameters. - foreach (var parameter in tree.Unmapped) + // Got a value provider? + if (parameter.ValueProvider != null) { - // Got a value provider? - if (parameter.ValueProvider != null) + var context = new CommandParameterContext(parameter, resolver, null); + if (parameter.ValueProvider.TryGetValue(context, out var result)) { - var context = new CommandParameterContext(parameter, resolver, null); - if (parameter.ValueProvider.TryGetValue(context, out var result)) - { - result = ConvertValue(resolver, lookup, binder, parameter, result); + result = ConvertValue(resolver, lookup, binder, parameter, result); - lookup.SetValue(parameter, result); - CommandValidator.ValidateParameter(parameter, lookup, resolver); - continue; - } + lookup.SetValue(parameter, result); + CommandValidator.ValidateParameter(parameter, lookup, resolver); + continue; } - - if (parameter.IsFlagValue()) - { - // Set the flag value to an empty, not set instance. - var instance = Activator.CreateInstance(parameter.ParameterType); - lookup.SetValue(parameter, instance); - } - else - { - // Is this an option with a default value? - if (parameter.DefaultValue != null) - { - var value = parameter.DefaultValue?.Value; - value = ConvertValue(resolver, lookup, binder, parameter, value); - - binder.Bind(parameter, resolver, value); - CommandValidator.ValidateParameter(parameter, lookup, resolver); - } - else if (Nullable.GetUnderlyingType(parameter.ParameterType) != null || - !parameter.ParameterType.IsValueType) - { - lookup.SetValue(parameter, null); - } - } - } - - // Process mapped parameters. - foreach (var mapped in tree.Mapped) - { - if (mapped.Parameter.WantRawValue) - { - // Just try to assign the raw value. - binder.Bind(mapped.Parameter, resolver, mapped.Value); - } - else - { - if (mapped.Parameter.IsFlagValue() && mapped.Value == null) - { - if (mapped.Parameter is CommandOption option && option.DefaultValue != null) - { - // Set the default value. - binder.Bind(mapped.Parameter, resolver, option.DefaultValue?.Value); - } - else - { - // Set the flag but not the value. - binder.Bind(mapped.Parameter, resolver, null); - } - } - else - { - var converter = GetConverter(lookup, binder, resolver, mapped.Parameter); - if (converter == null) - { - throw CommandRuntimeException.NoConverterFound(mapped.Parameter); - } - - // Assign the value to the parameter. - binder.Bind(mapped.Parameter, resolver, converter.ConvertFromInvariantString(mapped.Value)); - } - } - - // Got a value provider? - if (mapped.Parameter.ValueProvider != null) - { - var context = new CommandParameterContext(mapped.Parameter, resolver, mapped.Value); - if (mapped.Parameter.ValueProvider.TryGetValue(context, out var result)) - { - lookup.SetValue(mapped.Parameter, result); - } - } - - CommandValidator.ValidateParameter(mapped.Parameter, lookup, resolver); - } - - tree = tree.Next; - } - - return lookup; - } - - private static object? ConvertValue(ITypeResolver resolver, CommandValueLookup lookup, CommandValueBinder binder, CommandParameter parameter, object? result) - { - if (result != null && result.GetType() != parameter.ParameterType) - { - var converter = GetConverter(lookup, binder, resolver, parameter); - if (converter != null) - { - result = converter.ConvertFrom(result); - } - } - - return result; - } - - [SuppressMessage("Style", "IDE0019:Use pattern matching", Justification = "It's OK")] - private static TypeConverter? GetConverter(CommandValueLookup lookup, CommandValueBinder binder, ITypeResolver resolver, CommandParameter parameter) - { - if (parameter.Converter == null) - { - if (parameter.ParameterType.IsArray) - { - // Return a converter for each array item (not the whole array) - return TypeDescriptor.GetConverter(parameter.ParameterType.GetElementType()); } if (parameter.IsFlagValue()) { - // Is the optional value instanciated? - var value = lookup.GetValue(parameter) as IFlagValue; - if (value == null) - { - // Try to assign it with a null value. - // This will create the optional value instance without a value. - binder.Bind(parameter, resolver, null); - value = lookup.GetValue(parameter) as IFlagValue; - if (value == null) - { - throw new InvalidOperationException("Could not intialize optional value."); - } - } - - // Return a converter for the flag element type. - return TypeDescriptor.GetConverter(value.Type); + // Set the flag value to an empty, not set instance. + var instance = Activator.CreateInstance(parameter.ParameterType); + lookup.SetValue(parameter, instance); } + else + { + // Is this an option with a default value? + if (parameter.DefaultValue != null) + { + var value = parameter.DefaultValue?.Value; + value = ConvertValue(resolver, lookup, binder, parameter, value); - return TypeDescriptor.GetConverter(parameter.ParameterType); + binder.Bind(parameter, resolver, value); + CommandValidator.ValidateParameter(parameter, lookup, resolver); + } + else if (Nullable.GetUnderlyingType(parameter.ParameterType) != null || + !parameter.ParameterType.IsValueType) + { + lookup.SetValue(parameter, null); + } + } } - var type = Type.GetType(parameter.Converter.ConverterTypeName); - return resolver.Resolve(type) as TypeConverter; + // Process mapped parameters. + foreach (var mapped in tree.Mapped) + { + if (mapped.Parameter.WantRawValue) + { + // Just try to assign the raw value. + binder.Bind(mapped.Parameter, resolver, mapped.Value); + } + else + { + if (mapped.Parameter.IsFlagValue() && mapped.Value == null) + { + if (mapped.Parameter is CommandOption option && option.DefaultValue != null) + { + // Set the default value. + binder.Bind(mapped.Parameter, resolver, option.DefaultValue?.Value); + } + else + { + // Set the flag but not the value. + binder.Bind(mapped.Parameter, resolver, null); + } + } + else + { + var converter = GetConverter(lookup, binder, resolver, mapped.Parameter); + if (converter == null) + { + throw CommandRuntimeException.NoConverterFound(mapped.Parameter); + } + + // Assign the value to the parameter. + binder.Bind(mapped.Parameter, resolver, converter.ConvertFromInvariantString(mapped.Value)); + } + } + + // Got a value provider? + if (mapped.Parameter.ValueProvider != null) + { + var context = new CommandParameterContext(mapped.Parameter, resolver, mapped.Value); + if (mapped.Parameter.ValueProvider.TryGetValue(context, out var result)) + { + lookup.SetValue(mapped.Parameter, result); + } + } + + CommandValidator.ValidateParameter(mapped.Parameter, lookup, resolver); + } + + tree = tree.Next; } + + return lookup; } -} + + private static object? ConvertValue(ITypeResolver resolver, CommandValueLookup lookup, CommandValueBinder binder, CommandParameter parameter, object? result) + { + if (result != null && result.GetType() != parameter.ParameterType) + { + var converter = GetConverter(lookup, binder, resolver, parameter); + if (converter != null) + { + result = converter.ConvertFrom(result); + } + } + + return result; + } + + [SuppressMessage("Style", "IDE0019:Use pattern matching", Justification = "It's OK")] + private static TypeConverter? GetConverter(CommandValueLookup lookup, CommandValueBinder binder, ITypeResolver resolver, CommandParameter parameter) + { + if (parameter.Converter == null) + { + if (parameter.ParameterType.IsArray) + { + // Return a converter for each array item (not the whole array) + return TypeDescriptor.GetConverter(parameter.ParameterType.GetElementType()); + } + + if (parameter.IsFlagValue()) + { + // Is the optional value instanciated? + var value = lookup.GetValue(parameter) as IFlagValue; + if (value == null) + { + // Try to assign it with a null value. + // This will create the optional value instance without a value. + binder.Bind(parameter, resolver, null); + value = lookup.GetValue(parameter) as IFlagValue; + if (value == null) + { + throw new InvalidOperationException("Could not intialize optional value."); + } + } + + // Return a converter for the flag element type. + return TypeDescriptor.GetConverter(value.Type); + } + + return TypeDescriptor.GetConverter(parameter.ParameterType); + } + + var type = Type.GetType(parameter.Converter.ConverterTypeName); + return resolver.Resolve(type) as TypeConverter; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Collections/IMultiMap.cs b/src/Spectre.Console/Cli/Internal/Collections/IMultiMap.cs index dea8012..b0864c6 100644 --- a/src/Spectre.Console/Cli/Internal/Collections/IMultiMap.cs +++ b/src/Spectre.Console/Cli/Internal/Collections/IMultiMap.cs @@ -1,14 +1,13 @@ -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// Representation of a multi map. +/// +internal interface IMultiMap { /// - /// Representation of a multi map. + /// Adds a key and a value to the multi map. /// - internal interface IMultiMap - { - /// - /// Adds a key and a value to the multi map. - /// - /// The pair to add. - void Add((object? Key, object? Value) pair); - } -} + /// The pair to add. + void Add((object? Key, object? Value) pair); +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Collections/MultiMap.cs b/src/Spectre.Console/Cli/Internal/Collections/MultiMap.cs index 03fe449..72174b9 100644 --- a/src/Spectre.Console/Cli/Internal/Collections/MultiMap.cs +++ b/src/Spectre.Console/Cli/Internal/Collections/MultiMap.cs @@ -4,172 +4,171 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +[SuppressMessage("Performance", "CA1812: Avoid uninstantiated internal classes")] +internal sealed class MultiMap : IMultiMap, ILookup, IDictionary, IReadOnlyDictionary + where TKey : notnull { - [SuppressMessage("Performance", "CA1812: Avoid uninstantiated internal classes")] - internal sealed class MultiMap : IMultiMap, ILookup, IDictionary, IReadOnlyDictionary - where TKey : notnull + private readonly IDictionary _lookup; + private readonly IDictionary _dictionary; + + public int Count => _lookup.Count; + + public bool IsReadOnly => false; + + public ICollection Keys => _lookup.Keys; + + public ICollection Values => _dictionary.Values; + + IEnumerable IReadOnlyDictionary.Keys => _lookup.Keys; + + IEnumerable IReadOnlyDictionary.Values => _dictionary.Values; + + TValue IReadOnlyDictionary.this[TKey key] => _dictionary[key]; + + TValue IDictionary.this[TKey key] { - private readonly IDictionary _lookup; - private readonly IDictionary _dictionary; - - public int Count => _lookup.Count; - - public bool IsReadOnly => false; - - public ICollection Keys => _lookup.Keys; - - public ICollection Values => _dictionary.Values; - - IEnumerable IReadOnlyDictionary.Keys => _lookup.Keys; - - IEnumerable IReadOnlyDictionary.Values => _dictionary.Values; - - TValue IReadOnlyDictionary.this[TKey key] => _dictionary[key]; - - TValue IDictionary.this[TKey key] + get { - get + return _dictionary[key]; + } + set + { + Add(key, value); + } + } + + public IEnumerable this[TKey key] + { + get + { + if (_lookup.TryGetValue(key, out var group)) { - return _dictionary[key]; - } - set - { - Add(key, value); + return group; } + + return Array.Empty(); + } + } + + public MultiMap() + { + _lookup = new Dictionary(); + _dictionary = new Dictionary(); + } + + private sealed class MultiMapGrouping : IGrouping + { + private readonly List _items; + + public TKey Key { get; } + + public MultiMapGrouping(TKey key, List items) + { + Key = key; + _items = items; } - public IEnumerable this[TKey key] + public void Add(TValue value) { - get - { - if (_lookup.TryGetValue(key, out var group)) - { - return group; - } - - return Array.Empty(); - } + _items.Add(value); } - public MultiMap() + public IEnumerator GetEnumerator() { - _lookup = new Dictionary(); - _dictionary = new Dictionary(); - } - - private sealed class MultiMapGrouping : IGrouping - { - private readonly List _items; - - public TKey Key { get; } - - public MultiMapGrouping(TKey key, List items) - { - Key = key; - _items = items; - } - - public void Add(TValue value) - { - _items.Add(value); - } - - public IEnumerator GetEnumerator() - { - return _items.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - } - - public bool Contains(TKey key) - { - return _lookup.ContainsKey(key); - } - - public IEnumerator> GetEnumerator() - { - foreach (var group in _lookup.Values) - { - yield return group; - } + return _items.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } + } - public void Add(TKey key, TValue value) + public bool Contains(TKey key) + { + return _lookup.ContainsKey(key); + } + + public IEnumerator> GetEnumerator() + { + foreach (var group in _lookup.Values) { - if (!_lookup.ContainsKey(key)) - { - _lookup[key] = new MultiMapGrouping(key, new List()); - } - - _lookup[key].Add(value); - _dictionary[key] = value; - } - - public bool ContainsKey(TKey key) - { - return Contains(key); - } - - public bool Remove(TKey key) - { - return _lookup.Remove(key); - } - - public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) - { - return _dictionary.TryGetValue(key, out value); - } - - public void Add(KeyValuePair item) - { - Add(item.Key, item.Value); - } - - public void Clear() - { - _lookup.Clear(); - } - - public bool Contains(KeyValuePair item) - { - return Contains(item.Key); - } - - public void CopyTo(KeyValuePair[] array, int arrayIndex) - { - _dictionary.CopyTo(array, arrayIndex); - } - - public bool Remove(KeyValuePair item) - { - return Remove(item.Key); - } - - IEnumerator> IEnumerable>.GetEnumerator() - { - return _dictionary.GetEnumerator(); - } - - public void Add((object? Key, object? Value) pair) - { - if (pair.Key != null) - { -#pragma warning disable CS8604 // Possible null reference argument of value. -#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. - Add((TKey)pair.Key, (TValue)pair.Value); -#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type. -#pragma warning restore CS8604 // Possible null reference argument of value. - } + yield return group; } } -} + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public void Add(TKey key, TValue value) + { + if (!_lookup.ContainsKey(key)) + { + _lookup[key] = new MultiMapGrouping(key, new List()); + } + + _lookup[key].Add(value); + _dictionary[key] = value; + } + + public bool ContainsKey(TKey key) + { + return Contains(key); + } + + public bool Remove(TKey key) + { + return _lookup.Remove(key); + } + + public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) + { + return _dictionary.TryGetValue(key, out value); + } + + public void Add(KeyValuePair item) + { + Add(item.Key, item.Value); + } + + public void Clear() + { + _lookup.Clear(); + } + + public bool Contains(KeyValuePair item) + { + return Contains(item.Key); + } + + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + _dictionary.CopyTo(array, arrayIndex); + } + + public bool Remove(KeyValuePair item) + { + return Remove(item.Key); + } + + IEnumerator> IEnumerable>.GetEnumerator() + { + return _dictionary.GetEnumerator(); + } + + public void Add((object? Key, object? Value) pair) + { + if (pair.Key != null) + { +#pragma warning disable CS8604 // Possible null reference argument of value. +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. + Add((TKey)pair.Key, (TValue)pair.Value); +#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning restore CS8604 // Possible null reference argument of value. + } + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/CommandBinder.cs b/src/Spectre.Console/Cli/Internal/CommandBinder.cs index 4aed252..15e6618 100644 --- a/src/Spectre.Console/Cli/Internal/CommandBinder.cs +++ b/src/Spectre.Console/Cli/Internal/CommandBinder.cs @@ -1,31 +1,30 @@ using System; -namespace Spectre.Console.Cli -{ - internal static class CommandBinder - { - public static CommandSettings Bind(CommandTree? tree, Type settingsType, ITypeResolver resolver) - { - var lookup = CommandValueResolver.GetParameterValues(tree, resolver); +namespace Spectre.Console.Cli; - // Got a constructor with at least one name corresponding to a settings? - foreach (var constructor in settingsType.GetConstructors()) +internal static class CommandBinder +{ + public static CommandSettings Bind(CommandTree? tree, Type settingsType, ITypeResolver resolver) + { + var lookup = CommandValueResolver.GetParameterValues(tree, resolver); + + // Got a constructor with at least one name corresponding to a settings? + foreach (var constructor in settingsType.GetConstructors()) + { + var parameters = constructor.GetParameters(); + if (parameters.Length > 0) { - var parameters = constructor.GetParameters(); - if (parameters.Length > 0) + foreach (var parameter in parameters) { - foreach (var parameter in parameters) + if (lookup.HasParameterWithName(parameter?.Name)) { - if (lookup.HasParameterWithName(parameter?.Name)) - { - // Use constructor injection. - return CommandConstructorBinder.CreateSettings(lookup, constructor, resolver); - } + // Use constructor injection. + return CommandConstructorBinder.CreateSettings(lookup, constructor, resolver); } } } - - return CommandPropertyBinder.CreateSettings(lookup, settingsType, resolver); } + + return CommandPropertyBinder.CreateSettings(lookup, settingsType, resolver); } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/CommandExecutor.cs b/src/Spectre.Console/Cli/Internal/CommandExecutor.cs index c3f7b9d..ca9c483 100644 --- a/src/Spectre.Console/Cli/Internal/CommandExecutor.cs +++ b/src/Spectre.Console/Cli/Internal/CommandExecutor.cs @@ -4,115 +4,114 @@ using System.Linq; using System.Reflection; using System.Threading.Tasks; -namespace Spectre.Console.Cli -{ - internal sealed class CommandExecutor - { - private readonly ITypeRegistrar _registrar; +namespace Spectre.Console.Cli; - public CommandExecutor(ITypeRegistrar registrar) +internal sealed class CommandExecutor +{ + private readonly ITypeRegistrar _registrar; + + public CommandExecutor(ITypeRegistrar registrar) + { + _registrar = registrar ?? throw new ArgumentNullException(nameof(registrar)); + _registrar.Register(typeof(DefaultPairDeconstructor), typeof(DefaultPairDeconstructor)); + } + + public async Task Execute(IConfiguration configuration, IEnumerable args) + { + if (configuration == null) { - _registrar = registrar ?? throw new ArgumentNullException(nameof(registrar)); - _registrar.Register(typeof(DefaultPairDeconstructor), typeof(DefaultPairDeconstructor)); + throw new ArgumentNullException(nameof(configuration)); } - public async Task Execute(IConfiguration configuration, IEnumerable args) + _registrar.RegisterInstance(typeof(IConfiguration), configuration); + _registrar.RegisterLazy(typeof(IAnsiConsole), () => configuration.Settings.Console.GetConsole()); + + // Create the command model. + var model = CommandModelBuilder.Build(configuration); + _registrar.RegisterInstance(typeof(CommandModel), model); + _registrar.RegisterDependencies(model); + + // No default command? + if (model.DefaultCommand == null) { - if (configuration == null) + // Got at least one argument? + var firstArgument = args.FirstOrDefault(); + if (firstArgument != null) { - throw new ArgumentNullException(nameof(configuration)); - } - - _registrar.RegisterInstance(typeof(IConfiguration), configuration); - _registrar.RegisterLazy(typeof(IAnsiConsole), () => configuration.Settings.Console.GetConsole()); - - // Create the command model. - var model = CommandModelBuilder.Build(configuration); - _registrar.RegisterInstance(typeof(CommandModel), model); - _registrar.RegisterDependencies(model); - - // No default command? - if (model.DefaultCommand == null) - { - // Got at least one argument? - var firstArgument = args.FirstOrDefault(); - if (firstArgument != null) + // Asking for version? Kind of a hack, but it's alright. + // We should probably make this a bit better in the future. + if (firstArgument.Equals("--version", StringComparison.OrdinalIgnoreCase) || + firstArgument.Equals("-v", StringComparison.OrdinalIgnoreCase)) { - // Asking for version? Kind of a hack, but it's alright. - // We should probably make this a bit better in the future. - if (firstArgument.Equals("--version", StringComparison.OrdinalIgnoreCase) || - firstArgument.Equals("-v", StringComparison.OrdinalIgnoreCase)) - { - var console = configuration.Settings.Console.GetConsole(); - console.WriteLine(ResolveApplicationVersion(configuration)); - return 0; - } + var console = configuration.Settings.Console.GetConsole(); + console.WriteLine(ResolveApplicationVersion(configuration)); + return 0; } } - - // Parse and map the model against the arguments. - var parser = new CommandTreeParser(model, configuration.Settings); - var parsedResult = parser.Parse(args); - _registrar.RegisterInstance(typeof(CommandTreeParserResult), parsedResult); - - // Currently the root? - if (parsedResult.Tree == null) - { - // Display help. - configuration.Settings.Console.SafeRender(HelpWriter.Write(model)); - return 0; - } - - // Get the command to execute. - var leaf = parsedResult.Tree.GetLeafCommand(); - if (leaf.Command.IsBranch || leaf.ShowHelp) - { - // Branches can't be executed. Show help. - configuration.Settings.Console.SafeRender(HelpWriter.WriteCommand(model, leaf.Command)); - return leaf.ShowHelp ? 0 : 1; - } - - // Register the arguments with the container. - _registrar.RegisterInstance(typeof(IRemainingArguments), parsedResult.Remaining); - - // Create the resolver and the context. - using (var resolver = new TypeResolverAdapter(_registrar.Build())) - { - var context = new CommandContext(parsedResult.Remaining, leaf.Command.Name, leaf.Command.Data); - - // Execute the command tree. - return await Execute(leaf, parsedResult.Tree, context, resolver, configuration).ConfigureAwait(false); - } } - private static string ResolveApplicationVersion(IConfiguration configuration) + // Parse and map the model against the arguments. + var parser = new CommandTreeParser(model, configuration.Settings); + var parsedResult = parser.Parse(args); + _registrar.RegisterInstance(typeof(CommandTreeParserResult), parsedResult); + + // Currently the root? + if (parsedResult.Tree == null) { - return - configuration.Settings.ApplicationVersion ?? // potential override - VersionHelper.GetVersion(Assembly.GetEntryAssembly()); + // Display help. + configuration.Settings.Console.SafeRender(HelpWriter.Write(model)); + return 0; } - private static Task Execute( - CommandTree leaf, - CommandTree tree, - CommandContext context, - ITypeResolver resolver, - IConfiguration configuration) + // Get the command to execute. + var leaf = parsedResult.Tree.GetLeafCommand(); + if (leaf.Command.IsBranch || leaf.ShowHelp) { - // Bind the command tree against the settings. - var settings = CommandBinder.Bind(tree, leaf.Command.SettingsType, resolver); - configuration.Settings.Interceptor?.Intercept(context, settings); + // Branches can't be executed. Show help. + configuration.Settings.Console.SafeRender(HelpWriter.WriteCommand(model, leaf.Command)); + return leaf.ShowHelp ? 0 : 1; + } - // Create and validate the command. - var command = leaf.CreateCommand(resolver); - var validationResult = command.Validate(context, settings); - if (!validationResult.Successful) - { - throw CommandRuntimeException.ValidationFailed(validationResult); - } + // Register the arguments with the container. + _registrar.RegisterInstance(typeof(IRemainingArguments), parsedResult.Remaining); - // Execute the command. - return command.Execute(context, settings); + // Create the resolver and the context. + using (var resolver = new TypeResolverAdapter(_registrar.Build())) + { + var context = new CommandContext(parsedResult.Remaining, leaf.Command.Name, leaf.Command.Data); + + // Execute the command tree. + return await Execute(leaf, parsedResult.Tree, context, resolver, configuration).ConfigureAwait(false); } } -} + + private static string ResolveApplicationVersion(IConfiguration configuration) + { + return + configuration.Settings.ApplicationVersion ?? // potential override + VersionHelper.GetVersion(Assembly.GetEntryAssembly()); + } + + private static Task Execute( + CommandTree leaf, + CommandTree tree, + CommandContext context, + ITypeResolver resolver, + IConfiguration configuration) + { + // Bind the command tree against the settings. + var settings = CommandBinder.Bind(tree, leaf.Command.SettingsType, resolver); + configuration.Settings.Interceptor?.Intercept(context, settings); + + // Create and validate the command. + var command = leaf.CreateCommand(resolver); + var validationResult = command.Validate(context, settings); + if (!validationResult.Successful) + { + throw CommandRuntimeException.ValidationFailed(validationResult); + } + + // Execute the command. + return command.Execute(context, settings); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/CommandPart.cs b/src/Spectre.Console/Cli/Internal/CommandPart.cs index 8ba522e..3b0054a 100644 --- a/src/Spectre.Console/Cli/Internal/CommandPart.cs +++ b/src/Spectre.Console/Cli/Internal/CommandPart.cs @@ -1,8 +1,7 @@ -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal enum CommandPart { - internal enum CommandPart - { - CommandName, - LongOption, - } -} + CommandName, + LongOption, +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/CommandSuggestor.cs b/src/Spectre.Console/Cli/Internal/CommandSuggestor.cs index b9ca210..f08d0e3 100644 --- a/src/Spectre.Console/Cli/Internal/CommandSuggestor.cs +++ b/src/Spectre.Console/Cli/Internal/CommandSuggestor.cs @@ -1,77 +1,76 @@ using System; using System.Linq; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal static class CommandSuggestor { - internal static class CommandSuggestor + private const float SmallestDistance = 2f; + + public static CommandInfo? Suggest(CommandModel model, CommandInfo? command, string name) { - private const float SmallestDistance = 2f; + var result = (CommandInfo?)null; - public static CommandInfo? Suggest(CommandModel model, CommandInfo? command, string name) + var container = command ?? (ICommandContainer)model; + if (command?.IsDefaultCommand ?? false) { - var result = (CommandInfo?)null; - - var container = command ?? (ICommandContainer)model; - if (command?.IsDefaultCommand ?? false) - { - // Default commands have no children, - // so use the root commands here. - container = model; - } - - var score = float.MaxValue; - foreach (var child in container.Commands.Where(x => !x.IsHidden)) - { - var temp = Score(child.Name, name); - if (temp < score) - { - score = temp; - result = child; - } - } - - if (score <= SmallestDistance) - { - return result; - } - - return null; + // Default commands have no children, + // so use the root commands here. + container = model; } - private static float Score(string source, string target) + var score = float.MaxValue; + foreach (var child in container.Commands.Where(x => !x.IsHidden)) { - source = source.ToUpperInvariant(); - target = target.ToUpperInvariant(); - - var n = source.Length; - var m = target.Length; - - if (n == 0) + var temp = Score(child.Name, name); + if (temp < score) { - return m; + score = temp; + result = child; } - - if (m == 0) - { - return n; - } - - var d = new int[n + 1, m + 1]; - Enumerable.Range(0, n + 1).ToList().ForEach(i => d[i, 0] = i); - Enumerable.Range(0, m + 1).ToList().ForEach(i => d[0, i] = i); - - for (var sourceIndex = 1; sourceIndex <= n; sourceIndex++) - { - for (var targetIndex = 1; targetIndex <= m; targetIndex++) - { - var cost = (target[targetIndex - 1] == source[sourceIndex - 1]) ? 0 : 1; - d[sourceIndex, targetIndex] = Math.Min( - Math.Min(d[sourceIndex - 1, targetIndex] + 1, d[sourceIndex, targetIndex - 1] + 1), - d[sourceIndex - 1, targetIndex - 1] + cost); - } - } - - return d[n, m]; } + + if (score <= SmallestDistance) + { + return result; + } + + return null; } -} + + private static float Score(string source, string target) + { + source = source.ToUpperInvariant(); + target = target.ToUpperInvariant(); + + var n = source.Length; + var m = target.Length; + + if (n == 0) + { + return m; + } + + if (m == 0) + { + return n; + } + + var d = new int[n + 1, m + 1]; + Enumerable.Range(0, n + 1).ToList().ForEach(i => d[i, 0] = i); + Enumerable.Range(0, m + 1).ToList().ForEach(i => d[0, i] = i); + + for (var sourceIndex = 1; sourceIndex <= n; sourceIndex++) + { + for (var targetIndex = 1; targetIndex <= m; targetIndex++) + { + var cost = (target[targetIndex - 1] == source[sourceIndex - 1]) ? 0 : 1; + d[sourceIndex, targetIndex] = Math.Min( + Math.Min(d[sourceIndex - 1, targetIndex] + 1, d[sourceIndex, targetIndex - 1] + 1), + d[sourceIndex - 1, targetIndex - 1] + cost); + } + } + + return d[n, m]; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/CommandValidator.cs b/src/Spectre.Console/Cli/Internal/CommandValidator.cs index 39816de..c6ce253 100644 --- a/src/Spectre.Console/Cli/Internal/CommandValidator.cs +++ b/src/Spectre.Console/Cli/Internal/CommandValidator.cs @@ -1,46 +1,45 @@ -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal static class CommandValidator { - internal static class CommandValidator + public static void ValidateRequiredParameters(CommandTree? tree) { - public static void ValidateRequiredParameters(CommandTree? tree) + var node = tree?.GetRootCommand(); + while (node != null) { - var node = tree?.GetRootCommand(); - while (node != null) + foreach (var parameter in node.Unmapped) { - foreach (var parameter in node.Unmapped) + if (parameter.Required) { - if (parameter.Required) + switch (parameter) { - switch (parameter) - { - case CommandArgument argument: - throw CommandRuntimeException.MissingRequiredArgument(node, argument); - } + case CommandArgument argument: + throw CommandRuntimeException.MissingRequiredArgument(node, argument); } } - - node = node.Next; } + + node = node.Next; } + } - public static void ValidateParameter(CommandParameter parameter, CommandValueLookup settings, ITypeResolver resolver) + public static void ValidateParameter(CommandParameter parameter, CommandValueLookup settings, ITypeResolver resolver) + { + var assignedValue = settings.GetValue(parameter); + foreach (var validator in parameter.Validators) { - var assignedValue = settings.GetValue(parameter); - foreach (var validator in parameter.Validators) + var context = new CommandParameterContext(parameter, resolver, assignedValue); + var validationResult = validator.Validate(context); + if (!validationResult.Successful) { - var context = new CommandParameterContext(parameter, resolver, assignedValue); - var validationResult = validator.Validate(context); - if (!validationResult.Successful) - { - // If there is an error message specified in the parameter validator attribute, - // then use that one, otherwise use the validation result. - var result = string.IsNullOrWhiteSpace(validator.ErrorMessage) - ? validationResult - : ValidationResult.Error(validator.ErrorMessage); + // If there is an error message specified in the parameter validator attribute, + // then use that one, otherwise use the validation result. + var result = string.IsNullOrWhiteSpace(validator.ErrorMessage) + ? validationResult + : ValidationResult.Error(validator.ErrorMessage); - throw CommandRuntimeException.ValidationFailed(result); - } + throw CommandRuntimeException.ValidationFailed(result); } } } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Commands/ExplainCommand.cs b/src/Spectre.Console/Cli/Internal/Commands/ExplainCommand.cs index 49e49ca..a19a161 100644 --- a/src/Spectre.Console/Cli/Internal/Commands/ExplainCommand.cs +++ b/src/Spectre.Console/Cli/Internal/Commands/ExplainCommand.cs @@ -1,272 +1,271 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.Linq; using Spectre.Console.Rendering; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +[Description("Displays diagnostics about CLI configurations")] +[SuppressMessage("Performance", "CA1812: Avoid uninstantiated internal classes")] +internal sealed class ExplainCommand : Command { - [Description("Displays diagnostics about CLI configurations")] - [SuppressMessage("Performance", "CA1812: Avoid uninstantiated internal classes")] - internal sealed class ExplainCommand : Command + private readonly CommandModel _commandModel; + private readonly IAnsiConsole _writer; + + public ExplainCommand(IConfiguration configuration, CommandModel commandModel) { - private readonly CommandModel _commandModel; - private readonly IAnsiConsole _writer; + _commandModel = commandModel ?? throw new ArgumentNullException(nameof(commandModel)); + _writer = configuration.Settings.Console.GetConsole(); + } - public ExplainCommand(IConfiguration configuration, CommandModel commandModel) + public sealed class Settings : CommandSettings + { + public Settings(string[]? commands, bool? detailed, bool includeHidden) { - _commandModel = commandModel ?? throw new ArgumentNullException(nameof(commandModel)); - _writer = configuration.Settings.Console.GetConsole(); + Commands = commands; + Detailed = detailed; + IncludeHidden = includeHidden; } - public sealed class Settings : CommandSettings + [CommandArgument(0, "[command]")] + public string[]? Commands { get; } + + [Description("Include detailed information about the commands.")] + [CommandOption("-d|--detailed")] + public bool? Detailed { get; } + + [Description("Include hidden commands and options.")] + [CommandOption("--hidden")] + public bool IncludeHidden { get; } + } + + public override int Execute([NotNull] CommandContext context, [NotNull] Settings settings) + { + var tree = new Tree("CLI Configuration"); + tree.AddNode(ValueMarkup("Application Name", _commandModel.ApplicationName, "no application name")); + tree.AddNode(ValueMarkup("Parsing Mode", _commandModel.ParsingMode.ToString())); + + if (settings.Commands == null || settings.Commands.Length == 0) { - public Settings(string[]? commands, bool? detailed, bool includeHidden) - { - Commands = commands; - Detailed = detailed; - IncludeHidden = includeHidden; - } + // If there is a default command we'll want to include it in the list too. + var commands = _commandModel.DefaultCommand != null + ? new[] { _commandModel.DefaultCommand }.Concat(_commandModel.Commands) + : _commandModel.Commands; - [CommandArgument(0, "[command]")] - public string[]? Commands { get; } - - [Description("Include detailed information about the commands.")] - [CommandOption("-d|--detailed")] - public bool? Detailed { get; } - - [Description("Include hidden commands and options.")] - [CommandOption("--hidden")] - public bool IncludeHidden { get; } + AddCommands( + tree.AddNode(ParentMarkup("Commands")), + commands, + settings.Detailed ?? false, + settings.IncludeHidden); } - - public override int Execute([NotNull] CommandContext context, [NotNull] Settings settings) + else { - var tree = new Tree("CLI Configuration"); - tree.AddNode(ValueMarkup("Application Name", _commandModel.ApplicationName, "no application name")); - tree.AddNode(ValueMarkup("Parsing Mode", _commandModel.ParsingMode.ToString())); - - if (settings.Commands == null || settings.Commands.Length == 0) + var currentCommandTier = _commandModel.Commands; + CommandInfo? currentCommand = null; + foreach (var command in settings.Commands) { - // If there is a default command we'll want to include it in the list too. - var commands = _commandModel.DefaultCommand != null - ? new[] { _commandModel.DefaultCommand }.Concat(_commandModel.Commands) - : _commandModel.Commands; - - AddCommands( - tree.AddNode(ParentMarkup("Commands")), - commands, - settings.Detailed ?? false, - settings.IncludeHidden); - } - else - { - var currentCommandTier = _commandModel.Commands; - CommandInfo? currentCommand = null; - foreach (var command in settings.Commands) - { - currentCommand = currentCommandTier - .SingleOrDefault(i => - i.Name.Equals(command, StringComparison.CurrentCultureIgnoreCase) || - i.Aliases - .Any(alias => alias.Equals(command, StringComparison.CurrentCultureIgnoreCase))); - - if (currentCommand == null) - { - break; - } - - currentCommandTier = currentCommand.Children; - } + currentCommand = currentCommandTier + .SingleOrDefault(i => + i.Name.Equals(command, StringComparison.CurrentCultureIgnoreCase) || + i.Aliases + .Any(alias => alias.Equals(command, StringComparison.CurrentCultureIgnoreCase))); if (currentCommand == null) { - throw new Exception($"Command {string.Join(" ", settings.Commands)} not found"); + break; } - AddCommands( - tree.AddNode(ParentMarkup("Commands")), - new[] { currentCommand }, - settings.Detailed ?? true, - settings.IncludeHidden); + currentCommandTier = currentCommand.Children; } - _writer.Write(tree); + if (currentCommand == null) + { + throw new Exception($"Command {string.Join(" ", settings.Commands)} not found"); + } - return 0; + AddCommands( + tree.AddNode(ParentMarkup("Commands")), + new[] { currentCommand }, + settings.Detailed ?? true, + settings.IncludeHidden); } - private IRenderable ValueMarkup(string key, string value) + _writer.Write(tree); + + return 0; + } + + private IRenderable ValueMarkup(string key, string value) + { + return new Markup($"{key}: [blue]{value.EscapeMarkup()}[/]"); + } + + private IRenderable ValueMarkup(string key, string? value, string noValueText) + { + if (string.IsNullOrWhiteSpace(value)) { - return new Markup($"{key}: [blue]{value.EscapeMarkup()}[/]"); + return new Markup($"{key}: [grey]({noValueText.EscapeMarkup()})[/]"); } - private IRenderable ValueMarkup(string key, string? value, string noValueText) - { - if (string.IsNullOrWhiteSpace(value)) - { - return new Markup($"{key}: [grey]({noValueText.EscapeMarkup()})[/]"); - } + var table = new Table().NoBorder().HideHeaders().AddColumns("key", "value"); + table.AddRow($"{key}", $"[blue]{value.EscapeMarkup()}[/]"); + return table; + } - var table = new Table().NoBorder().HideHeaders().AddColumns("key", "value"); - table.AddRow($"{key}", $"[blue]{value.EscapeMarkup()}[/]"); - return table; + private string ParentMarkup(string description) + { + return $"[yellow]{description.EscapeMarkup()}[/]"; + } + + private void AddStringList(TreeNode node, string description, IList? strings) + { + if (strings == null || strings.Count == 0) + { + return; } - private string ParentMarkup(string description) + var parentNode = node.AddNode(ParentMarkup(description)); + foreach (var s in strings) { - return $"[yellow]{description.EscapeMarkup()}[/]"; - } - - private void AddStringList(TreeNode node, string description, IList? strings) - { - if (strings == null || strings.Count == 0) - { - return; - } - - var parentNode = node.AddNode(ParentMarkup(description)); - foreach (var s in strings) - { - parentNode.AddNode(s); - } - } - - private void AddCommands(TreeNode node, IEnumerable commands, bool detailed, bool includeHidden) - { - foreach (var command in commands) - { - if (!includeHidden && command.IsHidden) - { - continue; - } - - var commandName = $"[green]{command.Name}[/]"; - if (command.IsDefaultCommand) - { - commandName += " (default)"; - } - - var commandNode = node.AddNode(commandName); - commandNode.AddNode(ValueMarkup("Description", command.Description, "no description")); - if (command.IsHidden) - { - commandNode.AddNode(ValueMarkup("IsHidden", command.IsHidden.ToString())); - } - - if (!command.IsBranch) - { - commandNode.AddNode(ValueMarkup("Type", command.CommandType?.ToString(), "no command type")); - commandNode.AddNode(ValueMarkup("Settings Type", command.SettingsType.ToString())); - } - - if (command.Parameters.Count > 0) - { - var parametersNode = commandNode.AddNode(ParentMarkup("Parameters")); - foreach (var parameter in command.Parameters) - { - AddParameter(parametersNode, parameter, detailed, includeHidden); - } - } - - AddStringList(commandNode, "Aliases", command.Aliases.ToList()); - AddStringList(commandNode, "Examples", command.Examples.Select(i => string.Join(" ", i)).ToList()); - - if (command.Children.Count > 0) - { - var childNode = commandNode.AddNode(ParentMarkup("Child Commands")); - AddCommands(childNode, command.Children, detailed, includeHidden); - } - } - } - - private void AddParameter(TreeNode parametersNode, CommandParameter parameter, bool detailed, bool includeHidden) - { - if (!includeHidden && parameter.IsHidden) - { - return; - } - - if (!detailed) - { - parametersNode.AddNode( - $"{parameter.PropertyName} [purple]{GetShortOptions(parameter)}[/] [grey]{parameter.Property.PropertyType.ToString().EscapeMarkup()}[/]"); - - return; - } - - var parameterNode = parametersNode.AddNode( - $"{parameter.PropertyName} [grey]{parameter.Property.PropertyType.ToString().EscapeMarkup()}[/]"); - - parameterNode.AddNode(ValueMarkup("Description", parameter.Description, "no description")); - parameterNode.AddNode(ValueMarkup("Parameter Kind", parameter.ParameterKind.ToString())); - - if (parameter is CommandOption commandOptionParameter) - { - if (commandOptionParameter.IsShadowed) - { - parameterNode.AddNode(ValueMarkup("IsShadowed", commandOptionParameter.IsShadowed.ToString())); - } - - if (commandOptionParameter.LongNames.Count > 0) - { - parameterNode.AddNode(ValueMarkup( - "Long Names", - string.Join("|", commandOptionParameter.LongNames.Select(i => $"--{i}")))); - - parameterNode.AddNode(ValueMarkup( - "Short Names", - string.Join("|", commandOptionParameter.ShortNames.Select(i => $"-{i}")))); - } - } - else if (parameter is CommandArgument commandArgumentParameter) - { - parameterNode.AddNode(ValueMarkup("Position", commandArgumentParameter.Position.ToString())); - parameterNode.AddNode(ValueMarkup("Value", commandArgumentParameter.Value)); - } - - parameterNode.AddNode(ValueMarkup("Required", parameter.Required.ToString())); - - if (parameter.Converter != null) - { - parameterNode.AddNode(ValueMarkup( - "Converter", $"\"{parameter.Converter.ConverterTypeName}\"")); - } - - if (parameter.DefaultValue != null) - { - parameterNode.AddNode(ValueMarkup( - "Default Value", $"\"{parameter.DefaultValue.Value}\"")); - } - - if (parameter.PairDeconstructor != null) - { - parameterNode.AddNode(ValueMarkup("Pair Deconstructor", parameter.PairDeconstructor.Type.ToString())); - } - - AddStringList( - parameterNode, - "Validators", - parameter.Validators.Select(i => i.GetType().ToString()).ToList()); - } - - private static string GetShortOptions(CommandParameter parameter) - { - if (parameter is CommandOption commandOptionParameter) - { - return string.Join( - " | ", - commandOptionParameter.LongNames.Select(i => $"--{i}") - .Concat(commandOptionParameter.ShortNames.Select(i => $"-{i}"))); - } - - if (parameter is CommandArgument commandArgumentParameter) - { - return $"{commandArgumentParameter.Value} position {commandArgumentParameter.Position}"; - } - - return string.Empty; + parentNode.AddNode(s); } } + + private void AddCommands(TreeNode node, IEnumerable commands, bool detailed, bool includeHidden) + { + foreach (var command in commands) + { + if (!includeHidden && command.IsHidden) + { + continue; + } + + var commandName = $"[green]{command.Name}[/]"; + if (command.IsDefaultCommand) + { + commandName += " (default)"; + } + + var commandNode = node.AddNode(commandName); + commandNode.AddNode(ValueMarkup("Description", command.Description, "no description")); + if (command.IsHidden) + { + commandNode.AddNode(ValueMarkup("IsHidden", command.IsHidden.ToString())); + } + + if (!command.IsBranch) + { + commandNode.AddNode(ValueMarkup("Type", command.CommandType?.ToString(), "no command type")); + commandNode.AddNode(ValueMarkup("Settings Type", command.SettingsType.ToString())); + } + + if (command.Parameters.Count > 0) + { + var parametersNode = commandNode.AddNode(ParentMarkup("Parameters")); + foreach (var parameter in command.Parameters) + { + AddParameter(parametersNode, parameter, detailed, includeHidden); + } + } + + AddStringList(commandNode, "Aliases", command.Aliases.ToList()); + AddStringList(commandNode, "Examples", command.Examples.Select(i => string.Join(" ", i)).ToList()); + + if (command.Children.Count > 0) + { + var childNode = commandNode.AddNode(ParentMarkup("Child Commands")); + AddCommands(childNode, command.Children, detailed, includeHidden); + } + } + } + + private void AddParameter(TreeNode parametersNode, CommandParameter parameter, bool detailed, bool includeHidden) + { + if (!includeHidden && parameter.IsHidden) + { + return; + } + + if (!detailed) + { + parametersNode.AddNode( + $"{parameter.PropertyName} [purple]{GetShortOptions(parameter)}[/] [grey]{parameter.Property.PropertyType.ToString().EscapeMarkup()}[/]"); + + return; + } + + var parameterNode = parametersNode.AddNode( + $"{parameter.PropertyName} [grey]{parameter.Property.PropertyType.ToString().EscapeMarkup()}[/]"); + + parameterNode.AddNode(ValueMarkup("Description", parameter.Description, "no description")); + parameterNode.AddNode(ValueMarkup("Parameter Kind", parameter.ParameterKind.ToString())); + + if (parameter is CommandOption commandOptionParameter) + { + if (commandOptionParameter.IsShadowed) + { + parameterNode.AddNode(ValueMarkup("IsShadowed", commandOptionParameter.IsShadowed.ToString())); + } + + if (commandOptionParameter.LongNames.Count > 0) + { + parameterNode.AddNode(ValueMarkup( + "Long Names", + string.Join("|", commandOptionParameter.LongNames.Select(i => $"--{i}")))); + + parameterNode.AddNode(ValueMarkup( + "Short Names", + string.Join("|", commandOptionParameter.ShortNames.Select(i => $"-{i}")))); + } + } + else if (parameter is CommandArgument commandArgumentParameter) + { + parameterNode.AddNode(ValueMarkup("Position", commandArgumentParameter.Position.ToString())); + parameterNode.AddNode(ValueMarkup("Value", commandArgumentParameter.Value)); + } + + parameterNode.AddNode(ValueMarkup("Required", parameter.Required.ToString())); + + if (parameter.Converter != null) + { + parameterNode.AddNode(ValueMarkup( + "Converter", $"\"{parameter.Converter.ConverterTypeName}\"")); + } + + if (parameter.DefaultValue != null) + { + parameterNode.AddNode(ValueMarkup( + "Default Value", $"\"{parameter.DefaultValue.Value}\"")); + } + + if (parameter.PairDeconstructor != null) + { + parameterNode.AddNode(ValueMarkup("Pair Deconstructor", parameter.PairDeconstructor.Type.ToString())); + } + + AddStringList( + parameterNode, + "Validators", + parameter.Validators.Select(i => i.GetType().ToString()).ToList()); + } + + private static string GetShortOptions(CommandParameter parameter) + { + if (parameter is CommandOption commandOptionParameter) + { + return string.Join( + " | ", + commandOptionParameter.LongNames.Select(i => $"--{i}") + .Concat(commandOptionParameter.ShortNames.Select(i => $"-{i}"))); + } + + if (parameter is CommandArgument commandArgumentParameter) + { + return $"{commandArgumentParameter.Value} position {commandArgumentParameter.Position}"; + } + + return string.Empty; + } } \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Commands/VersionCommand.cs b/src/Spectre.Console/Cli/Internal/Commands/VersionCommand.cs index 2fae7ff..6bdb85c 100644 --- a/src/Spectre.Console/Cli/Internal/Commands/VersionCommand.cs +++ b/src/Spectre.Console/Cli/Internal/Commands/VersionCommand.cs @@ -1,34 +1,33 @@ using System.ComponentModel; using System.Diagnostics.CodeAnalysis; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +[Description("Displays the CLI library version")] +[SuppressMessage("Performance", "CA1812: Avoid uninstantiated internal classes")] +internal sealed class VersionCommand : Command { - [Description("Displays the CLI library version")] - [SuppressMessage("Performance", "CA1812: Avoid uninstantiated internal classes")] - internal sealed class VersionCommand : Command + private readonly IAnsiConsole _writer; + + public VersionCommand(IConfiguration configuration) { - private readonly IAnsiConsole _writer; - - public VersionCommand(IConfiguration configuration) - { - _writer = configuration.Settings.Console.GetConsole(); - } - - public sealed class Settings : CommandSettings - { - } - - public override int Execute([NotNull] CommandContext context, [NotNull] Settings settings) - { - _writer.MarkupLine( - "[yellow]Spectre.Cli[/] version [aqua]{0}[/]", - VersionHelper.GetVersion(typeof(VersionCommand)?.Assembly)); - - _writer.MarkupLine( - "[yellow]Spectre.Console[/] version [aqua]{0}[/]", - VersionHelper.GetVersion(typeof(IAnsiConsole)?.Assembly)); - - return 0; - } + _writer = configuration.Settings.Console.GetConsole(); } -} + + public sealed class Settings : CommandSettings + { + } + + public override int Execute([NotNull] CommandContext context, [NotNull] Settings settings) + { + _writer.MarkupLine( + "[yellow]Spectre.Cli[/] version [aqua]{0}[/]", + VersionHelper.GetVersion(typeof(VersionCommand)?.Assembly)); + + _writer.MarkupLine( + "[yellow]Spectre.Console[/] version [aqua]{0}[/]", + VersionHelper.GetVersion(typeof(IAnsiConsole)?.Assembly)); + + return 0; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Commands/XmlDocCommand.cs b/src/Spectre.Console/Cli/Internal/Commands/XmlDocCommand.cs index f4e36c9..1c02d6e 100644 --- a/src/Spectre.Console/Cli/Internal/Commands/XmlDocCommand.cs +++ b/src/Spectre.Console/Cli/Internal/Commands/XmlDocCommand.cs @@ -7,179 +7,178 @@ using System.Linq; using System.Text; using System.Xml; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +[Description("Generates an XML representation of the CLI configuration.")] +[SuppressMessage("Performance", "CA1812: Avoid uninstantiated internal classes")] +internal sealed class XmlDocCommand : Command { - [Description("Generates an XML representation of the CLI configuration.")] - [SuppressMessage("Performance", "CA1812: Avoid uninstantiated internal classes")] - internal sealed class XmlDocCommand : Command + private readonly CommandModel _model; + private readonly IAnsiConsole _writer; + + public XmlDocCommand(IConfiguration configuration, CommandModel model) { - private readonly CommandModel _model; - private readonly IAnsiConsole _writer; + _model = model ?? throw new ArgumentNullException(nameof(model)); + _writer = configuration.Settings.Console.GetConsole(); + } - public XmlDocCommand(IConfiguration configuration, CommandModel model) + public sealed class Settings : CommandSettings + { + } + + public override int Execute([NotNull] CommandContext context, [NotNull] Settings settings) + { + _writer.Write(Serialize(_model), Style.Plain); + return 0; + } + + public static string Serialize(CommandModel model) + { + var settings = new XmlWriterSettings { - _model = model ?? throw new ArgumentNullException(nameof(model)); - _writer = configuration.Settings.Console.GetConsole(); - } + Indent = true, + IndentChars = " ", + NewLineChars = "\n", + OmitXmlDeclaration = false, + Encoding = Encoding.UTF8, + }; - public sealed class Settings : CommandSettings + using (var buffer = new StringWriterWithEncoding(Encoding.UTF8)) + using (var xmlWriter = XmlWriter.Create(buffer, settings)) { - } - - public override int Execute([NotNull] CommandContext context, [NotNull] Settings settings) - { - _writer.Write(Serialize(_model), Style.Plain); - return 0; - } - - public static string Serialize(CommandModel model) - { - var settings = new XmlWriterSettings - { - Indent = true, - IndentChars = " ", - NewLineChars = "\n", - OmitXmlDeclaration = false, - Encoding = Encoding.UTF8, - }; - - using (var buffer = new StringWriterWithEncoding(Encoding.UTF8)) - using (var xmlWriter = XmlWriter.Create(buffer, settings)) - { - SerializeModel(model).WriteTo(xmlWriter); - xmlWriter.Flush(); - return buffer.GetStringBuilder().ToString(); - } - } - - private static XmlDocument SerializeModel(CommandModel model) - { - var document = new XmlDocument(); - var root = document.CreateElement("Model"); - - if (model.DefaultCommand != null) - { - root.AppendChild(document.CreateComment("DEFAULT COMMAND")); - root.AppendChild(CreateCommandNode(document, model.DefaultCommand, isDefaultCommand: true)); - } - - foreach (var command in model.Commands.Where(x => !x.IsHidden)) - { - root.AppendChild(document.CreateComment(command.Name.ToUpperInvariant())); - root.AppendChild(CreateCommandNode(document, command)); - } - - document.AppendChild(root); - return document; - } - - private static XmlNode CreateCommandNode(XmlDocument doc, CommandInfo command, bool isDefaultCommand = false) - { - var node = doc.CreateElement("Command"); - - // Attributes - node.SetNullableAttribute("Name", command.Name); - node.SetBooleanAttribute("IsBranch", command.IsBranch); - - if (isDefaultCommand) - { - node.SetBooleanAttribute("IsDefault", true); - } - - if (command.CommandType != null) - { - node.SetNullableAttribute("ClrType", command.CommandType?.FullName); - } - - node.SetNullableAttribute("Settings", command.SettingsType?.FullName); - - // Parameters - if (command.Parameters.Count > 0) - { - var parameterRootNode = doc.CreateElement("Parameters"); - foreach (var parameter in CreateParameterNodes(doc, command)) - { - parameterRootNode.AppendChild(parameter); - } - - node.AppendChild(parameterRootNode); - } - - // Commands - foreach (var childCommand in command.Children) - { - node.AppendChild(doc.CreateComment(childCommand.Name.ToUpperInvariant())); - node.AppendChild(CreateCommandNode(doc, childCommand)); - } - - return node; - } - - private static IEnumerable CreateParameterNodes(XmlDocument document, CommandInfo command) - { - // Arguments - foreach (var argument in command.Parameters.OfType().OrderBy(x => x.Position)) - { - var node = document.CreateElement("Argument"); - node.SetNullableAttribute("Name", argument.Value); - node.SetAttribute("Position", argument.Position.ToString(CultureInfo.InvariantCulture)); - node.SetBooleanAttribute("Required", argument.Required); - node.SetEnumAttribute("Kind", argument.ParameterKind); - node.SetNullableAttribute("ClrType", argument.ParameterType?.FullName); - - if (!string.IsNullOrWhiteSpace(argument.Description)) - { - var descriptionNode = document.CreateElement("Description"); - descriptionNode.InnerText = argument.Description; - node.AppendChild(descriptionNode); - } - - if (argument.Validators.Count > 0) - { - var validatorRootNode = document.CreateElement("Validators"); - foreach (var validator in argument.Validators.OrderBy(x => x.GetType().FullName)) - { - var validatorNode = document.CreateElement("Validator"); - validatorNode.SetNullableAttribute("ClrType", validator.GetType().FullName); - validatorNode.SetNullableAttribute("Message", validator.ErrorMessage); - validatorRootNode.AppendChild(validatorNode); - } - - node.AppendChild(validatorRootNode); - } - - yield return node; - } - - // Options - foreach (var option in command.Parameters.OfType() - .Where(x => !x.IsHidden) - .OrderBy(x => string.Join(",", x.LongNames)) - .ThenBy(x => string.Join(",", x.ShortNames))) - { - var node = document.CreateElement("Option"); - - if (option.IsShadowed) - { - node.SetBooleanAttribute("Shadowed", true); - } - - node.SetNullableAttribute("Short", option.ShortNames); - node.SetNullableAttribute("Long", option.LongNames); - node.SetNullableAttribute("Value", option.ValueName); - node.SetBooleanAttribute("Required", option.Required); - node.SetEnumAttribute("Kind", option.ParameterKind); - node.SetNullableAttribute("ClrType", option.ParameterType?.FullName); - - if (!string.IsNullOrWhiteSpace(option.Description)) - { - var descriptionNode = document.CreateElement("Description"); - descriptionNode.InnerText = option.Description; - node.AppendChild(descriptionNode); - } - - yield return node; - } + SerializeModel(model).WriteTo(xmlWriter); + xmlWriter.Flush(); + return buffer.GetStringBuilder().ToString(); } } -} + + private static XmlDocument SerializeModel(CommandModel model) + { + var document = new XmlDocument(); + var root = document.CreateElement("Model"); + + if (model.DefaultCommand != null) + { + root.AppendChild(document.CreateComment("DEFAULT COMMAND")); + root.AppendChild(CreateCommandNode(document, model.DefaultCommand, isDefaultCommand: true)); + } + + foreach (var command in model.Commands.Where(x => !x.IsHidden)) + { + root.AppendChild(document.CreateComment(command.Name.ToUpperInvariant())); + root.AppendChild(CreateCommandNode(document, command)); + } + + document.AppendChild(root); + return document; + } + + private static XmlNode CreateCommandNode(XmlDocument doc, CommandInfo command, bool isDefaultCommand = false) + { + var node = doc.CreateElement("Command"); + + // Attributes + node.SetNullableAttribute("Name", command.Name); + node.SetBooleanAttribute("IsBranch", command.IsBranch); + + if (isDefaultCommand) + { + node.SetBooleanAttribute("IsDefault", true); + } + + if (command.CommandType != null) + { + node.SetNullableAttribute("ClrType", command.CommandType?.FullName); + } + + node.SetNullableAttribute("Settings", command.SettingsType?.FullName); + + // Parameters + if (command.Parameters.Count > 0) + { + var parameterRootNode = doc.CreateElement("Parameters"); + foreach (var parameter in CreateParameterNodes(doc, command)) + { + parameterRootNode.AppendChild(parameter); + } + + node.AppendChild(parameterRootNode); + } + + // Commands + foreach (var childCommand in command.Children) + { + node.AppendChild(doc.CreateComment(childCommand.Name.ToUpperInvariant())); + node.AppendChild(CreateCommandNode(doc, childCommand)); + } + + return node; + } + + private static IEnumerable CreateParameterNodes(XmlDocument document, CommandInfo command) + { + // Arguments + foreach (var argument in command.Parameters.OfType().OrderBy(x => x.Position)) + { + var node = document.CreateElement("Argument"); + node.SetNullableAttribute("Name", argument.Value); + node.SetAttribute("Position", argument.Position.ToString(CultureInfo.InvariantCulture)); + node.SetBooleanAttribute("Required", argument.Required); + node.SetEnumAttribute("Kind", argument.ParameterKind); + node.SetNullableAttribute("ClrType", argument.ParameterType?.FullName); + + if (!string.IsNullOrWhiteSpace(argument.Description)) + { + var descriptionNode = document.CreateElement("Description"); + descriptionNode.InnerText = argument.Description; + node.AppendChild(descriptionNode); + } + + if (argument.Validators.Count > 0) + { + var validatorRootNode = document.CreateElement("Validators"); + foreach (var validator in argument.Validators.OrderBy(x => x.GetType().FullName)) + { + var validatorNode = document.CreateElement("Validator"); + validatorNode.SetNullableAttribute("ClrType", validator.GetType().FullName); + validatorNode.SetNullableAttribute("Message", validator.ErrorMessage); + validatorRootNode.AppendChild(validatorNode); + } + + node.AppendChild(validatorRootNode); + } + + yield return node; + } + + // Options + foreach (var option in command.Parameters.OfType() + .Where(x => !x.IsHidden) + .OrderBy(x => string.Join(",", x.LongNames)) + .ThenBy(x => string.Join(",", x.ShortNames))) + { + var node = document.CreateElement("Option"); + + if (option.IsShadowed) + { + node.SetBooleanAttribute("Shadowed", true); + } + + node.SetNullableAttribute("Short", option.ShortNames); + node.SetNullableAttribute("Long", option.LongNames); + node.SetNullableAttribute("Value", option.ValueName); + node.SetBooleanAttribute("Required", option.Required); + node.SetEnumAttribute("Kind", option.ParameterKind); + node.SetNullableAttribute("ClrType", option.ParameterType?.FullName); + + if (!string.IsNullOrWhiteSpace(option.Description)) + { + var descriptionNode = document.CreateElement("Description"); + descriptionNode.InnerText = option.Description; + node.AppendChild(descriptionNode); + } + + yield return node; + } + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Composer.cs b/src/Spectre.Console/Cli/Internal/Composer.cs index abdb3a3..83321f3 100644 --- a/src/Spectre.Console/Cli/Internal/Composer.cs +++ b/src/Spectre.Console/Cli/Internal/Composer.cs @@ -3,104 +3,103 @@ using System.Collections.Generic; using System.Text; using Spectre.Console.Rendering; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal sealed class Composer : IRenderable { - internal sealed class Composer : IRenderable + private readonly StringBuilder _content; + + public Composer() { - private readonly StringBuilder _content; - - public Composer() - { - _content = new StringBuilder(); - } - - public Composer Text(string text) - { - _content.Append(text); - return this; - } - - public Composer Style(string style, string text) - { - _content.Append('[').Append(style).Append(']'); - _content.Append(text.EscapeMarkup()); - _content.Append("[/]"); - return this; - } - - public Composer Style(string style, Action action) - { - _content.Append('[').Append(style).Append(']'); - action(this); - _content.Append("[/]"); - return this; - } - - public Composer Space() - { - return Spaces(1); - } - - public Composer Spaces(int count) - { - return Repeat(' ', count); - } - - public Composer Tab() - { - return Tabs(1); - } - - public Composer Tabs(int count) - { - return Spaces(count * 4); - } - - public Composer Repeat(char character, int count) - { - _content.Append(new string(character, count)); - return this; - } - - public Composer LineBreak() - { - return LineBreaks(1); - } - - public Composer LineBreaks(int count) - { - for (var i = 0; i < count; i++) - { - _content.Append(Environment.NewLine); - } - - return this; - } - - public Composer Join(string separator, IEnumerable composers) - { - if (composers != null) - { - Space(); - Text(string.Join(separator, composers)); - } - - return this; - } - - public Measurement Measure(RenderContext context, int maxWidth) - { - return ((IRenderable)new Markup(_content.ToString())).Measure(context, maxWidth); - } - - public IEnumerable Render(RenderContext context, int maxWidth) - { - return ((IRenderable)new Markup(_content.ToString())).Render(context, maxWidth); - } - - public override string ToString() - { - return _content.ToString(); - } + _content = new StringBuilder(); } -} + + public Composer Text(string text) + { + _content.Append(text); + return this; + } + + public Composer Style(string style, string text) + { + _content.Append('[').Append(style).Append(']'); + _content.Append(text.EscapeMarkup()); + _content.Append("[/]"); + return this; + } + + public Composer Style(string style, Action action) + { + _content.Append('[').Append(style).Append(']'); + action(this); + _content.Append("[/]"); + return this; + } + + public Composer Space() + { + return Spaces(1); + } + + public Composer Spaces(int count) + { + return Repeat(' ', count); + } + + public Composer Tab() + { + return Tabs(1); + } + + public Composer Tabs(int count) + { + return Spaces(count * 4); + } + + public Composer Repeat(char character, int count) + { + _content.Append(new string(character, count)); + return this; + } + + public Composer LineBreak() + { + return LineBreaks(1); + } + + public Composer LineBreaks(int count) + { + for (var i = 0; i < count; i++) + { + _content.Append(Environment.NewLine); + } + + return this; + } + + public Composer Join(string separator, IEnumerable composers) + { + if (composers != null) + { + Space(); + Text(string.Join(separator, composers)); + } + + return this; + } + + public Measurement Measure(RenderContext context, int maxWidth) + { + return ((IRenderable)new Markup(_content.ToString())).Measure(context, maxWidth); + } + + public IEnumerable Render(RenderContext context, int maxWidth) + { + return ((IRenderable)new Markup(_content.ToString())).Render(context, maxWidth); + } + + public override string ToString() + { + return _content.ToString(); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Composition/Activators.cs b/src/Spectre.Console/Cli/Internal/Composition/Activators.cs index 9150418..bec575f 100644 --- a/src/Spectre.Console/Cli/Internal/Composition/Activators.cs +++ b/src/Spectre.Console/Cli/Internal/Composition/Activators.cs @@ -2,132 +2,131 @@ using System; using System.Collections.Generic; using System.Reflection; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal abstract class ComponentActivator { - internal abstract class ComponentActivator - { - public abstract object Activate(DefaultTypeResolver container); + public abstract object Activate(DefaultTypeResolver container); - public abstract ComponentActivator CreateCopy(); + public abstract ComponentActivator CreateCopy(); +} + +internal class CachingActivator : ComponentActivator +{ + private readonly ComponentActivator _activator; + private object? _result; + + public CachingActivator(ComponentActivator activator) + { + _activator = activator ?? throw new ArgumentNullException(nameof(activator)); + _result = null; } - internal class CachingActivator : ComponentActivator + public override object Activate(DefaultTypeResolver container) { - private readonly ComponentActivator _activator; - private object? _result; + return _result ??= _activator.Activate(container); + } - public CachingActivator(ComponentActivator activator) - { - _activator = activator ?? throw new ArgumentNullException(nameof(activator)); - _result = null; - } + public override ComponentActivator CreateCopy() + { + return new CachingActivator(_activator.CreateCopy()); + } +} - public override object Activate(DefaultTypeResolver container) - { - return _result ??= _activator.Activate(container); - } +internal sealed class InstanceActivator : ComponentActivator +{ + private readonly object _instance; - public override ComponentActivator CreateCopy() + public InstanceActivator(object instance) + { + _instance = instance; + } + + public override object Activate(DefaultTypeResolver container) + { + return _instance; + } + + public override ComponentActivator CreateCopy() + { + return new InstanceActivator(_instance); + } +} + +internal sealed class ReflectionActivator : ComponentActivator +{ + private readonly Type _type; + private readonly ConstructorInfo _constructor; + private readonly List _parameters; + + public ReflectionActivator(Type type) + { + _type = type; + _constructor = GetGreediestConstructor(type); + _parameters = new List(); + + foreach (var parameter in _constructor.GetParameters()) { - return new CachingActivator(_activator.CreateCopy()); + _parameters.Add(parameter); } } - internal sealed class InstanceActivator : ComponentActivator + public override object Activate(DefaultTypeResolver container) { - private readonly object _instance; - - public InstanceActivator(object instance) + var parameters = new object?[_parameters.Count]; + for (var i = 0; i < _parameters.Count; i++) { - _instance = instance; - } - - public override object Activate(DefaultTypeResolver container) - { - return _instance; - } - - public override ComponentActivator CreateCopy() - { - return new InstanceActivator(_instance); - } - } - - internal sealed class ReflectionActivator : ComponentActivator - { - private readonly Type _type; - private readonly ConstructorInfo _constructor; - private readonly List _parameters; - - public ReflectionActivator(Type type) - { - _type = type; - _constructor = GetGreediestConstructor(type); - _parameters = new List(); - - foreach (var parameter in _constructor.GetParameters()) + var parameter = _parameters[i]; + if (parameter.ParameterType == typeof(DefaultTypeResolver)) { - _parameters.Add(parameter); + parameters[i] = container; } - } - - public override object Activate(DefaultTypeResolver container) - { - var parameters = new object?[_parameters.Count]; - for (var i = 0; i < _parameters.Count; i++) + else { - var parameter = _parameters[i]; - if (parameter.ParameterType == typeof(DefaultTypeResolver)) + var resolved = container.Resolve(parameter.ParameterType); + if (resolved == null) { - parameters[i] = container; + if (!parameter.IsOptional) + { + throw new InvalidOperationException($"Could not find registration for '{parameter.ParameterType.FullName}'."); + } + + parameters[i] = null; } else { - var resolved = container.Resolve(parameter.ParameterType); - if (resolved == null) - { - if (!parameter.IsOptional) - { - throw new InvalidOperationException($"Could not find registration for '{parameter.ParameterType.FullName}'."); - } - - parameters[i] = null; - } - else - { - parameters[i] = resolved; - } + parameters[i] = resolved; } } - - return _constructor.Invoke(parameters); } - public override ComponentActivator CreateCopy() + return _constructor.Invoke(parameters); + } + + public override ComponentActivator CreateCopy() + { + return new ReflectionActivator(_type); + } + + private static ConstructorInfo GetGreediestConstructor(Type type) + { + ConstructorInfo? current = null; + var count = -1; + foreach (var constructor in type.GetTypeInfo().GetConstructors()) { - return new ReflectionActivator(_type); + var parameters = constructor.GetParameters(); + if (parameters.Length > count) + { + count = parameters.Length; + current = constructor; + } } - private static ConstructorInfo GetGreediestConstructor(Type type) + if (current == null) { - ConstructorInfo? current = null; - var count = -1; - foreach (var constructor in type.GetTypeInfo().GetConstructors()) - { - var parameters = constructor.GetParameters(); - if (parameters.Length > count) - { - count = parameters.Length; - current = constructor; - } - } - - if (current == null) - { - throw new InvalidOperationException($"Could not find a constructor for '{type.FullName}'."); - } - - return current; + throw new InvalidOperationException($"Could not find a constructor for '{type.FullName}'."); } + + return current; } } \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Composition/ComponentRegistration.cs b/src/Spectre.Console/Cli/Internal/Composition/ComponentRegistration.cs index ff1a8fc..9732db3 100644 --- a/src/Spectre.Console/Cli/Internal/Composition/ComponentRegistration.cs +++ b/src/Spectre.Console/Cli/Internal/Composition/ComponentRegistration.cs @@ -1,31 +1,30 @@ using System; using System.Collections.Generic; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal sealed class ComponentRegistration { - internal sealed class ComponentRegistration + public Type ImplementationType { get; } + public ComponentActivator Activator { get; } + public IReadOnlyList RegistrationTypes { get; } + + public ComponentRegistration(Type type, ComponentActivator activator, IEnumerable? registrationTypes = null) { - public Type ImplementationType { get; } - public ComponentActivator Activator { get; } - public IReadOnlyList RegistrationTypes { get; } - - public ComponentRegistration(Type type, ComponentActivator activator, IEnumerable? registrationTypes = null) + var registrations = new List(registrationTypes ?? Array.Empty()); + if (registrations.Count == 0) { - var registrations = new List(registrationTypes ?? Array.Empty()); - if (registrations.Count == 0) - { - // Every registration needs at least one registration type. - registrations.Add(type); - } - - ImplementationType = type; - RegistrationTypes = registrations; - Activator = activator ?? throw new ArgumentNullException(nameof(activator)); + // Every registration needs at least one registration type. + registrations.Add(type); } - public ComponentRegistration CreateCopy() - { - return new ComponentRegistration(ImplementationType, Activator.CreateCopy(), RegistrationTypes); - } + ImplementationType = type; + RegistrationTypes = registrations; + Activator = activator ?? throw new ArgumentNullException(nameof(activator)); + } + + public ComponentRegistration CreateCopy() + { + return new ComponentRegistration(ImplementationType, Activator.CreateCopy(), RegistrationTypes); } } \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Composition/ComponentRegistry.cs b/src/Spectre.Console/Cli/Internal/Composition/ComponentRegistry.cs index d4ee9b1..94c6410 100644 --- a/src/Spectre.Console/Cli/Internal/Composition/ComponentRegistry.cs +++ b/src/Spectre.Console/Cli/Internal/Composition/ComponentRegistry.cs @@ -2,59 +2,58 @@ using System; using System.Collections.Generic; using System.Linq; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal sealed class ComponentRegistry : IDisposable { - internal sealed class ComponentRegistry : IDisposable + private readonly Dictionary> _registrations; + + public ComponentRegistry() { - private readonly Dictionary> _registrations; + _registrations = new Dictionary>(); + } - public ComponentRegistry() + public ComponentRegistry CreateCopy() + { + var registry = new ComponentRegistry(); + foreach (var registration in _registrations.SelectMany(p => p.Value)) { - _registrations = new Dictionary>(); + registry.Register(registration.CreateCopy()); } - public ComponentRegistry CreateCopy() - { - var registry = new ComponentRegistry(); - foreach (var registration in _registrations.SelectMany(p => p.Value)) - { - registry.Register(registration.CreateCopy()); - } + return registry; + } - return registry; + public void Dispose() + { + foreach (var registration in _registrations) + { + registration.Value.Clear(); } - public void Dispose() + _registrations.Clear(); + } + + public void Register(ComponentRegistration registration) + { + foreach (var type in new HashSet(registration.RegistrationTypes)) { - foreach (var registration in _registrations) + if (!_registrations.ContainsKey(type)) { - registration.Value.Clear(); + _registrations.Add(type, new HashSet()); } - _registrations.Clear(); - } - - public void Register(ComponentRegistration registration) - { - foreach (var type in new HashSet(registration.RegistrationTypes)) - { - if (!_registrations.ContainsKey(type)) - { - _registrations.Add(type, new HashSet()); - } - - _registrations[type].Add(registration); - } - } - - public ICollection GetRegistrations(Type type) - { - if (_registrations.ContainsKey(type)) - { - return _registrations[type]; - } - - return new List(); + _registrations[type].Add(registration); } } + + public ICollection GetRegistrations(Type type) + { + if (_registrations.ContainsKey(type)) + { + return _registrations[type]; + } + + return new List(); + } } \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Composition/DefaultTypeRegistrar.cs b/src/Spectre.Console/Cli/Internal/Composition/DefaultTypeRegistrar.cs index 701ba41..948c80a 100644 --- a/src/Spectre.Console/Cli/Internal/Composition/DefaultTypeRegistrar.cs +++ b/src/Spectre.Console/Cli/Internal/Composition/DefaultTypeRegistrar.cs @@ -1,55 +1,54 @@ using System; using System.Collections.Generic; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal sealed class DefaultTypeRegistrar : ITypeRegistrar { - internal sealed class DefaultTypeRegistrar : ITypeRegistrar + private readonly Queue> _registry; + + public DefaultTypeRegistrar() { - private readonly Queue> _registry; - - public DefaultTypeRegistrar() - { - _registry = new Queue>(); - } - - public ITypeResolver Build() - { - var container = new DefaultTypeResolver(); - while (_registry.Count > 0) - { - var action = _registry.Dequeue(); - action(container.Registry); - } - - return container; - } - - public void Register(Type service, Type implementation) - { - var registration = new ComponentRegistration(implementation, new ReflectionActivator(implementation), new[] { service }); - _registry.Enqueue(registry => registry.Register(registration)); - } - - public void RegisterInstance(Type service, object implementation) - { - var registration = new ComponentRegistration(service, new CachingActivator(new InstanceActivator(implementation))); - _registry.Enqueue(registry => registry.Register(registration)); - } - - public void RegisterLazy(Type service, Func factory) - { - if (factory is null) - { - throw new ArgumentNullException(nameof(factory)); - } - - _registry.Enqueue(registry => - { - var activator = new CachingActivator(new InstanceActivator(factory())); - var registration = new ComponentRegistration(service, activator); - - registry.Register(registration); - }); - } + _registry = new Queue>(); } -} + + public ITypeResolver Build() + { + var container = new DefaultTypeResolver(); + while (_registry.Count > 0) + { + var action = _registry.Dequeue(); + action(container.Registry); + } + + return container; + } + + public void Register(Type service, Type implementation) + { + var registration = new ComponentRegistration(implementation, new ReflectionActivator(implementation), new[] { service }); + _registry.Enqueue(registry => registry.Register(registration)); + } + + public void RegisterInstance(Type service, object implementation) + { + var registration = new ComponentRegistration(service, new CachingActivator(new InstanceActivator(implementation))); + _registry.Enqueue(registry => registry.Register(registration)); + } + + public void RegisterLazy(Type service, Func factory) + { + if (factory is null) + { + throw new ArgumentNullException(nameof(factory)); + } + + _registry.Enqueue(registry => + { + var activator = new CachingActivator(new InstanceActivator(factory())); + var registration = new ComponentRegistration(service, activator); + + registry.Register(registration); + }); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Composition/DefaultTypeResolver.cs b/src/Spectre.Console/Cli/Internal/Composition/DefaultTypeResolver.cs index 4c2e38f..a0a714e 100644 --- a/src/Spectre.Console/Cli/Internal/Composition/DefaultTypeResolver.cs +++ b/src/Spectre.Console/Cli/Internal/Composition/DefaultTypeResolver.cs @@ -2,66 +2,65 @@ using System; using System.Collections.Generic; using System.Linq; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal sealed class DefaultTypeResolver : IDisposable, ITypeResolver { - internal sealed class DefaultTypeResolver : IDisposable, ITypeResolver + public ComponentRegistry Registry { get; } + + public DefaultTypeResolver() + : this(null) { - public ComponentRegistry Registry { get; } + } - public DefaultTypeResolver() - : this(null) + public DefaultTypeResolver(ComponentRegistry? registry) + { + Registry = registry ?? new ComponentRegistry(); + } + + public void Dispose() + { + Registry.Dispose(); + } + + public object? Resolve(Type? type) + { + if (type == null) { + return null; } - public DefaultTypeResolver(ComponentRegistry? registry) + var isEnumerable = false; + if (type.IsGenericType) { - Registry = registry ?? new ComponentRegistry(); - } - - public void Dispose() - { - Registry.Dispose(); - } - - public object? Resolve(Type? type) - { - if (type == null) + if (type.GetGenericTypeDefinition() == typeof(IEnumerable<>)) { - return null; + isEnumerable = true; + type = type.GenericTypeArguments[0]; } + } - var isEnumerable = false; - if (type.IsGenericType) + var registrations = Registry.GetRegistrations(type); + if (registrations != null) + { + if (isEnumerable) { - if (type.GetGenericTypeDefinition() == typeof(IEnumerable<>)) + var result = Array.CreateInstance(type, registrations.Count); + for (var index = 0; index < registrations.Count; index++) { - isEnumerable = true; - type = type.GenericTypeArguments[0]; + var registration = registrations.ElementAt(index); + result.SetValue(Resolve(registration), index); } + + return result; } - - var registrations = Registry.GetRegistrations(type); - if (registrations != null) - { - if (isEnumerable) - { - var result = Array.CreateInstance(type, registrations.Count); - for (var index = 0; index < registrations.Count; index++) - { - var registration = registrations.ElementAt(index); - result.SetValue(Resolve(registration), index); - } - - return result; - } - } - - return Resolve(registrations?.LastOrDefault()); } - public object? Resolve(ComponentRegistration? registration) - { - return registration?.Activator?.Activate(this); - } + return Resolve(registrations?.LastOrDefault()); + } + + public object? Resolve(ComponentRegistration? registration) + { + return registration?.Activator?.Activate(this); } } \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Configuration/CommandAppSettings.cs b/src/Spectre.Console/Cli/Internal/Configuration/CommandAppSettings.cs index 726d6fd..798399c 100644 --- a/src/Spectre.Console/Cli/Internal/Configuration/CommandAppSettings.cs +++ b/src/Spectre.Console/Cli/Internal/Configuration/CommandAppSettings.cs @@ -1,47 +1,46 @@ using System; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal sealed class CommandAppSettings : ICommandAppSettings { - internal sealed class CommandAppSettings : ICommandAppSettings + public string? ApplicationName { get; set; } + public string? ApplicationVersion { get; set; } + public IAnsiConsole? Console { get; set; } + public ICommandInterceptor? Interceptor { get; set; } + public ITypeRegistrarFrontend Registrar { get; set; } + public CaseSensitivity CaseSensitivity { get; set; } + public bool PropagateExceptions { get; set; } + public bool ValidateExamples { get; set; } + public bool StrictParsing { get; set; } + + public ParsingMode ParsingMode => + StrictParsing ? ParsingMode.Strict : ParsingMode.Relaxed; + + public Func? ExceptionHandler { get; set; } + + public CommandAppSettings(ITypeRegistrar registrar) { - public string? ApplicationName { get; set; } - public string? ApplicationVersion { get; set; } - public IAnsiConsole? Console { get; set; } - public ICommandInterceptor? Interceptor { get; set; } - public ITypeRegistrarFrontend Registrar { get; set; } - public CaseSensitivity CaseSensitivity { get; set; } - public bool PropagateExceptions { get; set; } - public bool ValidateExamples { get; set; } - public bool StrictParsing { get; set; } + Registrar = new TypeRegistrar(registrar); + CaseSensitivity = CaseSensitivity.All; + } - public ParsingMode ParsingMode => - StrictParsing ? ParsingMode.Strict : ParsingMode.Relaxed; - - public Func? ExceptionHandler { get; set; } - - public CommandAppSettings(ITypeRegistrar registrar) + public bool IsTrue(Func func, string environmentVariableName) + { + if (func(this)) { - Registrar = new TypeRegistrar(registrar); - CaseSensitivity = CaseSensitivity.All; + return true; } - public bool IsTrue(Func func, string environmentVariableName) + var environmentVariable = Environment.GetEnvironmentVariable(environmentVariableName); + if (!string.IsNullOrWhiteSpace(environmentVariable)) { - if (func(this)) + if (environmentVariable.Equals("True", StringComparison.OrdinalIgnoreCase)) { return true; } - - var environmentVariable = Environment.GetEnvironmentVariable(environmentVariableName); - if (!string.IsNullOrWhiteSpace(environmentVariable)) - { - if (environmentVariable.Equals("True", StringComparison.OrdinalIgnoreCase)) - { - return true; - } - } - - return false; } + + return false; } } \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Configuration/CommandConfigurator.cs b/src/Spectre.Console/Cli/Internal/Configuration/CommandConfigurator.cs index 75d22bf..b276aff 100644 --- a/src/Spectre.Console/Cli/Internal/Configuration/CommandConfigurator.cs +++ b/src/Spectre.Console/Cli/Internal/Configuration/CommandConfigurator.cs @@ -1,42 +1,41 @@ -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal sealed class CommandConfigurator : ICommandConfigurator { - internal sealed class CommandConfigurator : ICommandConfigurator + public ConfiguredCommand Command { get; } + + public CommandConfigurator(ConfiguredCommand command) { - public ConfiguredCommand Command { get; } - - public CommandConfigurator(ConfiguredCommand command) - { - Command = command; - } - - public ICommandConfigurator WithExample(string[] args) - { - Command.Examples.Add(args); - return this; - } - - public ICommandConfigurator WithAlias(string alias) - { - Command.Aliases.Add(alias); - return this; - } - - public ICommandConfigurator WithDescription(string description) - { - Command.Description = description; - return this; - } - - public ICommandConfigurator WithData(object data) - { - Command.Data = data; - return this; - } - - public ICommandConfigurator IsHidden() - { - Command.IsHidden = true; - return this; - } + Command = command; } -} + + public ICommandConfigurator WithExample(string[] args) + { + Command.Examples.Add(args); + return this; + } + + public ICommandConfigurator WithAlias(string alias) + { + Command.Aliases.Add(alias); + return this; + } + + public ICommandConfigurator WithDescription(string description) + { + Command.Description = description; + return this; + } + + public ICommandConfigurator WithData(object data) + { + Command.Data = data; + return this; + } + + public ICommandConfigurator IsHidden() + { + Command.IsHidden = true; + return this; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Configuration/ConfigurationHelper.cs b/src/Spectre.Console/Cli/Internal/Configuration/ConfigurationHelper.cs index 7812ea8..e1265a0 100644 --- a/src/Spectre.Console/Cli/Internal/Configuration/ConfigurationHelper.cs +++ b/src/Spectre.Console/Cli/Internal/Configuration/ConfigurationHelper.cs @@ -2,42 +2,41 @@ using System; using System.Diagnostics.CodeAnalysis; using System.Reflection; -namespace Spectre.Console.Cli -{ - internal static class ConfigurationHelper - { - public static Type? GetSettingsType(Type commandType) - { - if (typeof(ICommand).GetTypeInfo().IsAssignableFrom(commandType) && - GetGenericTypeArguments(commandType, typeof(ICommand<>), out var result)) - { - return result[0]; - } +namespace Spectre.Console.Cli; - return null; +internal static class ConfigurationHelper +{ + public static Type? GetSettingsType(Type commandType) + { + if (typeof(ICommand).GetTypeInfo().IsAssignableFrom(commandType) && + GetGenericTypeArguments(commandType, typeof(ICommand<>), out var result)) + { + return result[0]; } - private static bool GetGenericTypeArguments(Type? type, Type genericType, - [NotNullWhen(true)] out Type[]? genericTypeArguments) - { - while (type != null) - { - foreach (var @interface in type.GetTypeInfo().GetInterfaces()) - { - if (!@interface.GetTypeInfo().IsGenericType || @interface.GetGenericTypeDefinition() != genericType) - { - continue; - } + return null; + } - genericTypeArguments = @interface.GenericTypeArguments; - return true; + private static bool GetGenericTypeArguments(Type? type, Type genericType, + [NotNullWhen(true)] out Type[]? genericTypeArguments) + { + while (type != null) + { + foreach (var @interface in type.GetTypeInfo().GetInterfaces()) + { + if (!@interface.GetTypeInfo().IsGenericType || @interface.GetGenericTypeDefinition() != genericType) + { + continue; } - type = type.GetTypeInfo().BaseType; + genericTypeArguments = @interface.GenericTypeArguments; + return true; } - genericTypeArguments = null; - return false; + type = type.GetTypeInfo().BaseType; } + + genericTypeArguments = null; + return false; } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Configuration/Configurator.cs b/src/Spectre.Console/Cli/Internal/Configuration/Configurator.cs index 108196d..ac4e54e 100644 --- a/src/Spectre.Console/Cli/Internal/Configuration/Configurator.cs +++ b/src/Spectre.Console/Cli/Internal/Configuration/Configurator.cs @@ -2,94 +2,93 @@ using System; using System.Collections.Generic; using Spectre.Console.Cli.Unsafe; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal sealed class Configurator : IUnsafeConfigurator, IConfigurator, IConfiguration { - internal sealed class Configurator : IUnsafeConfigurator, IConfigurator, IConfiguration + private readonly ITypeRegistrar _registrar; + + public IList Commands { get; } + public CommandAppSettings Settings { get; } + public ConfiguredCommand? DefaultCommand { get; private set; } + public IList Examples { get; } + + ICommandAppSettings IConfigurator.Settings => Settings; + + public Configurator(ITypeRegistrar registrar) { - private readonly ITypeRegistrar _registrar; + _registrar = registrar; - public IList Commands { get; } - public CommandAppSettings Settings { get; } - public ConfiguredCommand? DefaultCommand { get; private set; } - public IList Examples { get; } - - ICommandAppSettings IConfigurator.Settings => Settings; - - public Configurator(ITypeRegistrar registrar) - { - _registrar = registrar; - - Commands = new List(); - Settings = new CommandAppSettings(registrar); - Examples = new List(); - } - - public void AddExample(string[] args) - { - Examples.Add(args); - } - - public void SetDefaultCommand() - where TDefaultCommand : class, ICommand - { - DefaultCommand = ConfiguredCommand.FromType( - CliConstants.DefaultCommandName, isDefaultCommand: true); - } - - public ICommandConfigurator AddCommand(string name) - where TCommand : class, ICommand - { - var command = Commands.AddAndReturn(ConfiguredCommand.FromType(name, false)); - return new CommandConfigurator(command); - } - - public ICommandConfigurator AddDelegate(string name, Func func) - where TSettings : CommandSettings - { - var command = Commands.AddAndReturn(ConfiguredCommand.FromDelegate( - name, (context, settings) => func(context, (TSettings)settings))); - return new CommandConfigurator(command); - } - - public void AddBranch(string name, Action> action) - where TSettings : CommandSettings - { - var command = ConfiguredCommand.FromBranch(name); - action(new Configurator(command, _registrar)); - Commands.Add(command); - } - - ICommandConfigurator IUnsafeConfigurator.AddCommand(string name, Type command) - { - var method = GetType().GetMethod("AddCommand"); - if (method == null) - { - throw new CommandConfigurationException("Could not find AddCommand by reflection."); - } - - method = method.MakeGenericMethod(command); - - if (!(method.Invoke(this, new object[] { name }) is ICommandConfigurator result)) - { - throw new CommandConfigurationException("Invoking AddCommand returned null."); - } - - return result; - } - - void IUnsafeConfigurator.AddBranch(string name, Type settings, Action action) - { - var command = ConfiguredCommand.FromBranch(settings, name); - - // Create the configurator. - var configuratorType = typeof(Configurator<>).MakeGenericType(settings); - if (!(Activator.CreateInstance(configuratorType, new object?[] { command, _registrar }) is IUnsafeBranchConfigurator configurator)) - { - throw new CommandConfigurationException("Could not create configurator by reflection."); - } - - action(configurator); - Commands.Add(command); - } + Commands = new List(); + Settings = new CommandAppSettings(registrar); + Examples = new List(); } -} + + public void AddExample(string[] args) + { + Examples.Add(args); + } + + public void SetDefaultCommand() + where TDefaultCommand : class, ICommand + { + DefaultCommand = ConfiguredCommand.FromType( + CliConstants.DefaultCommandName, isDefaultCommand: true); + } + + public ICommandConfigurator AddCommand(string name) + where TCommand : class, ICommand + { + var command = Commands.AddAndReturn(ConfiguredCommand.FromType(name, false)); + return new CommandConfigurator(command); + } + + public ICommandConfigurator AddDelegate(string name, Func func) + where TSettings : CommandSettings + { + var command = Commands.AddAndReturn(ConfiguredCommand.FromDelegate( + name, (context, settings) => func(context, (TSettings)settings))); + return new CommandConfigurator(command); + } + + public void AddBranch(string name, Action> action) + where TSettings : CommandSettings + { + var command = ConfiguredCommand.FromBranch(name); + action(new Configurator(command, _registrar)); + Commands.Add(command); + } + + ICommandConfigurator IUnsafeConfigurator.AddCommand(string name, Type command) + { + var method = GetType().GetMethod("AddCommand"); + if (method == null) + { + throw new CommandConfigurationException("Could not find AddCommand by reflection."); + } + + method = method.MakeGenericMethod(command); + + if (!(method.Invoke(this, new object[] { name }) is ICommandConfigurator result)) + { + throw new CommandConfigurationException("Invoking AddCommand returned null."); + } + + return result; + } + + void IUnsafeConfigurator.AddBranch(string name, Type settings, Action action) + { + var command = ConfiguredCommand.FromBranch(settings, name); + + // Create the configurator. + var configuratorType = typeof(Configurator<>).MakeGenericType(settings); + if (!(Activator.CreateInstance(configuratorType, new object?[] { command, _registrar }) is IUnsafeBranchConfigurator configurator)) + { + throw new CommandConfigurationException("Could not create configurator by reflection."); + } + + action(configurator); + Commands.Add(command); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Configuration/ConfiguratorOfT.cs b/src/Spectre.Console/Cli/Internal/Configuration/ConfiguratorOfT.cs index c8f2656..075cc0d 100644 --- a/src/Spectre.Console/Cli/Internal/Configuration/ConfiguratorOfT.cs +++ b/src/Spectre.Console/Cli/Internal/Configuration/ConfiguratorOfT.cs @@ -1,94 +1,93 @@ using System; using Spectre.Console.Cli.Unsafe; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal sealed class Configurator : IUnsafeBranchConfigurator, IConfigurator + where TSettings : CommandSettings { - internal sealed class Configurator : IUnsafeBranchConfigurator, IConfigurator - where TSettings : CommandSettings + private readonly ConfiguredCommand _command; + private readonly ITypeRegistrar? _registrar; + + public Configurator(ConfiguredCommand command, ITypeRegistrar? registrar) { - private readonly ConfiguredCommand _command; - private readonly ITypeRegistrar? _registrar; - - public Configurator(ConfiguredCommand command, ITypeRegistrar? registrar) - { - _command = command; - _registrar = registrar; - } - - public void SetDescription(string description) - { - _command.Description = description; - } - - public void AddExample(string[] args) - { - _command.Examples.Add(args); - } - - public void HideBranch() - { - _command.IsHidden = true; - } - - public ICommandConfigurator AddCommand(string name) - where TCommand : class, ICommandLimiter - { - var command = ConfiguredCommand.FromType(name); - var configurator = new CommandConfigurator(command); - - _command.Children.Add(command); - return configurator; - } - - public ICommandConfigurator AddDelegate(string name, Func func) - where TDerivedSettings : TSettings - { - var command = ConfiguredCommand.FromDelegate( - name, (context, settings) => func(context, (TDerivedSettings)settings)); - - _command.Children.Add(command); - return new CommandConfigurator(command); - } - - public void AddBranch(string name, Action> action) - where TDerivedSettings : TSettings - { - var command = ConfiguredCommand.FromBranch(name); - action(new Configurator(command, _registrar)); - _command.Children.Add(command); - } - - ICommandConfigurator IUnsafeConfigurator.AddCommand(string name, Type command) - { - var method = GetType().GetMethod("AddCommand"); - if (method == null) - { - throw new CommandConfigurationException("Could not find AddCommand by reflection."); - } - - method = method.MakeGenericMethod(command); - - if (!(method.Invoke(this, new object[] { name }) is ICommandConfigurator result)) - { - throw new CommandConfigurationException("Invoking AddCommand returned null."); - } - - return result; - } - - void IUnsafeConfigurator.AddBranch(string name, Type settings, Action action) - { - var command = ConfiguredCommand.FromBranch(settings, name); - - // Create the configurator. - var configuratorType = typeof(Configurator<>).MakeGenericType(settings); - if (!(Activator.CreateInstance(configuratorType, new object?[] { command, _registrar }) is IUnsafeBranchConfigurator configurator)) - { - throw new CommandConfigurationException("Could not create configurator by reflection."); - } - - action(configurator); - _command.Children.Add(command); - } + _command = command; + _registrar = registrar; } -} + + public void SetDescription(string description) + { + _command.Description = description; + } + + public void AddExample(string[] args) + { + _command.Examples.Add(args); + } + + public void HideBranch() + { + _command.IsHidden = true; + } + + public ICommandConfigurator AddCommand(string name) + where TCommand : class, ICommandLimiter + { + var command = ConfiguredCommand.FromType(name); + var configurator = new CommandConfigurator(command); + + _command.Children.Add(command); + return configurator; + } + + public ICommandConfigurator AddDelegate(string name, Func func) + where TDerivedSettings : TSettings + { + var command = ConfiguredCommand.FromDelegate( + name, (context, settings) => func(context, (TDerivedSettings)settings)); + + _command.Children.Add(command); + return new CommandConfigurator(command); + } + + public void AddBranch(string name, Action> action) + where TDerivedSettings : TSettings + { + var command = ConfiguredCommand.FromBranch(name); + action(new Configurator(command, _registrar)); + _command.Children.Add(command); + } + + ICommandConfigurator IUnsafeConfigurator.AddCommand(string name, Type command) + { + var method = GetType().GetMethod("AddCommand"); + if (method == null) + { + throw new CommandConfigurationException("Could not find AddCommand by reflection."); + } + + method = method.MakeGenericMethod(command); + + if (!(method.Invoke(this, new object[] { name }) is ICommandConfigurator result)) + { + throw new CommandConfigurationException("Invoking AddCommand returned null."); + } + + return result; + } + + void IUnsafeConfigurator.AddBranch(string name, Type settings, Action action) + { + var command = ConfiguredCommand.FromBranch(settings, name); + + // Create the configurator. + var configuratorType = typeof(Configurator<>).MakeGenericType(settings); + if (!(Activator.CreateInstance(configuratorType, new object?[] { command, _registrar }) is IUnsafeBranchConfigurator configurator)) + { + throw new CommandConfigurationException("Could not create configurator by reflection."); + } + + action(configurator); + _command.Children.Add(command); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Configuration/ConfiguredCommand.cs b/src/Spectre.Console/Cli/Internal/Configuration/ConfiguredCommand.cs index 06a065a..a8cc312 100644 --- a/src/Spectre.Console/Cli/Internal/Configuration/ConfiguredCommand.cs +++ b/src/Spectre.Console/Cli/Internal/Configuration/ConfiguredCommand.cs @@ -1,69 +1,68 @@ using System; using System.Collections.Generic; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal sealed class ConfiguredCommand { - internal sealed class ConfiguredCommand + public string Name { get; } + public HashSet Aliases { get; } + public string? Description { get; set; } + public object? Data { get; set; } + public Type? CommandType { get; } + public Type SettingsType { get; } + public Func? Delegate { get; } + public bool IsDefaultCommand { get; } + public bool IsHidden { get; set; } + + public IList Children { get; } + public IList Examples { get; } + + private ConfiguredCommand( + string name, + Type? commandType, + Type settingsType, + Func? @delegate, + bool isDefaultCommand) { - public string Name { get; } - public HashSet Aliases { get; } - public string? Description { get; set; } - public object? Data { get; set; } - public Type? CommandType { get; } - public Type SettingsType { get; } - public Func? Delegate { get; } - public bool IsDefaultCommand { get; } - public bool IsHidden { get; set; } + Name = name; + Aliases = new HashSet(StringComparer.OrdinalIgnoreCase); + CommandType = commandType; + SettingsType = settingsType; + Delegate = @delegate; + IsDefaultCommand = isDefaultCommand; - public IList Children { get; } - public IList Examples { get; } - - private ConfiguredCommand( - string name, - Type? commandType, - Type settingsType, - Func? @delegate, - bool isDefaultCommand) - { - Name = name; - Aliases = new HashSet(StringComparer.OrdinalIgnoreCase); - CommandType = commandType; - SettingsType = settingsType; - Delegate = @delegate; - IsDefaultCommand = isDefaultCommand; - - Children = new List(); - Examples = new List(); - } - - public static ConfiguredCommand FromBranch(Type settings, string name) - { - return new ConfiguredCommand(name, null, settings, null, false); - } - - public static ConfiguredCommand FromBranch(string name) - where TSettings : CommandSettings - { - return new ConfiguredCommand(name, null, typeof(TSettings), null, false); - } - - public static ConfiguredCommand FromType(string name, bool isDefaultCommand = false) - where TCommand : class, ICommand - { - var settingsType = ConfigurationHelper.GetSettingsType(typeof(TCommand)); - if (settingsType == null) - { - throw CommandRuntimeException.CouldNotGetSettingsType(typeof(TCommand)); - } - - return new ConfiguredCommand(name, typeof(TCommand), settingsType, null, isDefaultCommand); - } - - public static ConfiguredCommand FromDelegate( - string name, Func? @delegate = null) - where TSettings : CommandSettings - { - return new ConfiguredCommand(name, null, typeof(TSettings), @delegate, false); - } + Children = new List(); + Examples = new List(); } -} + + public static ConfiguredCommand FromBranch(Type settings, string name) + { + return new ConfiguredCommand(name, null, settings, null, false); + } + + public static ConfiguredCommand FromBranch(string name) + where TSettings : CommandSettings + { + return new ConfiguredCommand(name, null, typeof(TSettings), null, false); + } + + public static ConfiguredCommand FromType(string name, bool isDefaultCommand = false) + where TCommand : class, ICommand + { + var settingsType = ConfigurationHelper.GetSettingsType(typeof(TCommand)); + if (settingsType == null) + { + throw CommandRuntimeException.CouldNotGetSettingsType(typeof(TCommand)); + } + + return new ConfiguredCommand(name, typeof(TCommand), settingsType, null, isDefaultCommand); + } + + public static ConfiguredCommand FromDelegate( + string name, Func? @delegate = null) + where TSettings : CommandSettings + { + return new ConfiguredCommand(name, null, typeof(TSettings), @delegate, false); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Configuration/IConfiguration.cs b/src/Spectre.Console/Cli/Internal/Configuration/IConfiguration.cs index 6477eb3..65724df 100644 --- a/src/Spectre.Console/Cli/Internal/Configuration/IConfiguration.cs +++ b/src/Spectre.Console/Cli/Internal/Configuration/IConfiguration.cs @@ -1,30 +1,29 @@ using System.Collections.Generic; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// Represents a configuration. +/// +internal interface IConfiguration { /// - /// Represents a configuration. + /// Gets the configured commands. /// - internal interface IConfiguration - { - /// - /// Gets the configured commands. - /// - IList Commands { get; } + IList Commands { get; } - /// - /// Gets the settings for the configuration. - /// - CommandAppSettings Settings { get; } + /// + /// Gets the settings for the configuration. + /// + CommandAppSettings Settings { get; } - /// - /// Gets the default command for the configuration. - /// - ConfiguredCommand? DefaultCommand { get; } + /// + /// Gets the default command for the configuration. + /// + ConfiguredCommand? DefaultCommand { get; } - /// - /// Gets all examples for the configuration. - /// - IList Examples { get; } - } + /// + /// Gets all examples for the configuration. + /// + IList Examples { get; } } \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Configuration/TemplateParser.cs b/src/Spectre.Console/Cli/Internal/Configuration/TemplateParser.cs index 3656bb7..0d4736b 100644 --- a/src/Spectre.Console/Cli/Internal/Configuration/TemplateParser.cs +++ b/src/Spectre.Console/Cli/Internal/Configuration/TemplateParser.cs @@ -1,149 +1,148 @@ using System.Collections.Generic; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal static class TemplateParser { - internal static class TemplateParser + public sealed class ArgumentResult { - public sealed class ArgumentResult + public string Value { get; set; } + public bool Required { get; set; } + + public ArgumentResult(string value, bool required) { - public string Value { get; set; } - public bool Required { get; set; } - - public ArgumentResult(string value, bool required) - { - Value = value; - Required = required; - } - } - - public sealed class OptionResult - { - public List LongNames { get; set; } - public List ShortNames { get; set; } - public string? Value { get; set; } - public bool ValueIsOptional { get; set; } - - public OptionResult() - { - ShortNames = new List(); - LongNames = new List(); - } - } - - public static ArgumentResult ParseArgumentTemplate(string template) - { - var valueName = default(string); - var required = false; - foreach (var token in TemplateTokenizer.Tokenize(template)) - { - if (token.TokenKind == TemplateToken.Kind.ShortName || - token.TokenKind == TemplateToken.Kind.LongName) - { - throw CommandTemplateException.ArgumentCannotContainOptions(template, token); - } - - if (token.TokenKind == TemplateToken.Kind.OptionalValue || - token.TokenKind == TemplateToken.Kind.RequiredValue) - { - if (!string.IsNullOrWhiteSpace(valueName)) - { - throw CommandTemplateException.MultipleValuesAreNotSupported(template, token); - } - - if (string.IsNullOrWhiteSpace(token.Value)) - { - throw CommandTemplateException.ValuesMustHaveName(template, token); - } - - valueName = token.Value; - required = token.TokenKind == TemplateToken.Kind.RequiredValue; - } - } - - if (valueName == null) - { - throw CommandTemplateException.ArgumentsMustHaveValueName(template); - } - - return new ArgumentResult(valueName, required); - } - - public static OptionResult ParseOptionTemplate(string template) - { - var result = new OptionResult(); - - foreach (var token in TemplateTokenizer.Tokenize(template)) - { - if (token.TokenKind == TemplateToken.Kind.LongName || token.TokenKind == TemplateToken.Kind.ShortName) - { - if (string.IsNullOrWhiteSpace(token.Value)) - { - throw CommandTemplateException.OptionsMustHaveName(template, token); - } - - if (char.IsDigit(token.Value[0])) - { - throw CommandTemplateException.OptionNamesCannotStartWithDigit(template, token); - } - - foreach (var character in token.Value) - { - if (!char.IsLetterOrDigit(character) && character != '-' && character != '_') - { - throw CommandTemplateException.InvalidCharacterInOptionName(template, token, character); - } - } - } - - if (token.TokenKind == TemplateToken.Kind.LongName) - { - if (token.Value.Length == 1) - { - throw CommandTemplateException.LongOptionMustHaveMoreThanOneCharacter(template, token); - } - - result.LongNames.Add(token.Value); - } - - if (token.TokenKind == TemplateToken.Kind.ShortName) - { - if (token.Value.Length > 1) - { - throw CommandTemplateException.ShortOptionMustOnlyBeOneCharacter(template, token); - } - - result.ShortNames.Add(token.Value); - } - - if (token.TokenKind == TemplateToken.Kind.RequiredValue || - token.TokenKind == TemplateToken.Kind.OptionalValue) - { - if (!string.IsNullOrWhiteSpace(result.Value)) - { - throw CommandTemplateException.MultipleOptionValuesAreNotSupported(template, token); - } - - foreach (var character in token.Value) - { - if (!char.IsLetterOrDigit(character) && - character != '=' && character != '-' && character != '_') - { - throw CommandTemplateException.InvalidCharacterInValueName(template, token, character); - } - } - - result.Value = token.Value.ToUpperInvariant(); - result.ValueIsOptional = token.TokenKind == TemplateToken.Kind.OptionalValue; - } - } - - if (result.LongNames.Count == 0 && - result.ShortNames.Count == 0) - { - throw CommandTemplateException.MissingLongAndShortName(template, null); - } - - return result; + Value = value; + Required = required; } } -} + + public sealed class OptionResult + { + public List LongNames { get; set; } + public List ShortNames { get; set; } + public string? Value { get; set; } + public bool ValueIsOptional { get; set; } + + public OptionResult() + { + ShortNames = new List(); + LongNames = new List(); + } + } + + public static ArgumentResult ParseArgumentTemplate(string template) + { + var valueName = default(string); + var required = false; + foreach (var token in TemplateTokenizer.Tokenize(template)) + { + if (token.TokenKind == TemplateToken.Kind.ShortName || + token.TokenKind == TemplateToken.Kind.LongName) + { + throw CommandTemplateException.ArgumentCannotContainOptions(template, token); + } + + if (token.TokenKind == TemplateToken.Kind.OptionalValue || + token.TokenKind == TemplateToken.Kind.RequiredValue) + { + if (!string.IsNullOrWhiteSpace(valueName)) + { + throw CommandTemplateException.MultipleValuesAreNotSupported(template, token); + } + + if (string.IsNullOrWhiteSpace(token.Value)) + { + throw CommandTemplateException.ValuesMustHaveName(template, token); + } + + valueName = token.Value; + required = token.TokenKind == TemplateToken.Kind.RequiredValue; + } + } + + if (valueName == null) + { + throw CommandTemplateException.ArgumentsMustHaveValueName(template); + } + + return new ArgumentResult(valueName, required); + } + + public static OptionResult ParseOptionTemplate(string template) + { + var result = new OptionResult(); + + foreach (var token in TemplateTokenizer.Tokenize(template)) + { + if (token.TokenKind == TemplateToken.Kind.LongName || token.TokenKind == TemplateToken.Kind.ShortName) + { + if (string.IsNullOrWhiteSpace(token.Value)) + { + throw CommandTemplateException.OptionsMustHaveName(template, token); + } + + if (char.IsDigit(token.Value[0])) + { + throw CommandTemplateException.OptionNamesCannotStartWithDigit(template, token); + } + + foreach (var character in token.Value) + { + if (!char.IsLetterOrDigit(character) && character != '-' && character != '_') + { + throw CommandTemplateException.InvalidCharacterInOptionName(template, token, character); + } + } + } + + if (token.TokenKind == TemplateToken.Kind.LongName) + { + if (token.Value.Length == 1) + { + throw CommandTemplateException.LongOptionMustHaveMoreThanOneCharacter(template, token); + } + + result.LongNames.Add(token.Value); + } + + if (token.TokenKind == TemplateToken.Kind.ShortName) + { + if (token.Value.Length > 1) + { + throw CommandTemplateException.ShortOptionMustOnlyBeOneCharacter(template, token); + } + + result.ShortNames.Add(token.Value); + } + + if (token.TokenKind == TemplateToken.Kind.RequiredValue || + token.TokenKind == TemplateToken.Kind.OptionalValue) + { + if (!string.IsNullOrWhiteSpace(result.Value)) + { + throw CommandTemplateException.MultipleOptionValuesAreNotSupported(template, token); + } + + foreach (var character in token.Value) + { + if (!char.IsLetterOrDigit(character) && + character != '=' && character != '-' && character != '_') + { + throw CommandTemplateException.InvalidCharacterInValueName(template, token, character); + } + } + + result.Value = token.Value.ToUpperInvariant(); + result.ValueIsOptional = token.TokenKind == TemplateToken.Kind.OptionalValue; + } + } + + if (result.LongNames.Count == 0 && + result.ShortNames.Count == 0) + { + throw CommandTemplateException.MissingLongAndShortName(template, null); + } + + return result; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Configuration/TemplateToken.cs b/src/Spectre.Console/Cli/Internal/Configuration/TemplateToken.cs index c48d150..a5f7a48 100644 --- a/src/Spectre.Console/Cli/Internal/Configuration/TemplateToken.cs +++ b/src/Spectre.Console/Cli/Internal/Configuration/TemplateToken.cs @@ -1,27 +1,26 @@ -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal sealed class TemplateToken { - internal sealed class TemplateToken + public Kind TokenKind { get; } + public int Position { get; } + public string Value { get; } + public string Representation { get; } + + public TemplateToken(Kind kind, int position, string value, string representation) { - public Kind TokenKind { get; } - public int Position { get; } - public string Value { get; } - public string Representation { get; } + TokenKind = kind; + Position = position; + Value = value; + Representation = representation; + } - public TemplateToken(Kind kind, int position, string value, string representation) - { - TokenKind = kind; - Position = position; - Value = value; - Representation = representation; - } - - public enum Kind - { - Unknown = 0, - LongName, - ShortName, - RequiredValue, - OptionalValue, - } + public enum Kind + { + Unknown = 0, + LongName, + ShortName, + RequiredValue, + OptionalValue, } } \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Configuration/TemplateTokenizer.cs b/src/Spectre.Console/Cli/Internal/Configuration/TemplateTokenizer.cs index 0a59bf2..6787672 100644 --- a/src/Spectre.Console/Cli/Internal/Configuration/TemplateTokenizer.cs +++ b/src/Spectre.Console/Cli/Internal/Configuration/TemplateTokenizer.cs @@ -1,135 +1,134 @@ using System.Collections.Generic; using System.Text; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal static class TemplateTokenizer { - internal static class TemplateTokenizer + public static IReadOnlyList Tokenize(string template) { - public static IReadOnlyList Tokenize(string template) + using var buffer = new TextBuffer(template); + var result = new List(); + + while (!buffer.ReachedEnd) { - using var buffer = new TextBuffer(template); - var result = new List(); + EatWhitespace(buffer); - while (!buffer.ReachedEnd) + if (!buffer.TryPeek(out var character)) { - EatWhitespace(buffer); - - if (!buffer.TryPeek(out var character)) - { - break; - } - - if (character == '-') - { - result.Add(ReadOption(buffer)); - } - else if (character == '|') - { - buffer.Consume('|'); - } - else if (character == '<') - { - result.Add(ReadValue(buffer, true)); - } - else if (character == '[') - { - result.Add(ReadValue(buffer, false)); - } - else - { - throw CommandTemplateException.UnexpectedCharacter(buffer.Original, buffer.Position, character); - } + break; } - return result; - } - - private static void EatWhitespace(TextBuffer buffer) - { - while (!buffer.ReachedEnd) + if (character == '-') { - var character = buffer.Peek(); - if (!char.IsWhiteSpace(character)) - { - break; - } - - buffer.Read(); + result.Add(ReadOption(buffer)); + } + else if (character == '|') + { + buffer.Consume('|'); + } + else if (character == '<') + { + result.Add(ReadValue(buffer, true)); + } + else if (character == '[') + { + result.Add(ReadValue(buffer, false)); + } + else + { + throw CommandTemplateException.UnexpectedCharacter(buffer.Original, buffer.Position, character); } } - private static TemplateToken ReadOption(TextBuffer buffer) + return result; + } + + private static void EatWhitespace(TextBuffer buffer) + { + while (!buffer.ReachedEnd) { - var position = buffer.Position; - - buffer.Consume('-'); - if (buffer.IsNext('-')) + var character = buffer.Peek(); + if (!char.IsWhiteSpace(character)) { - buffer.Consume('-'); - var longValue = ReadOptionName(buffer); - return new TemplateToken(TemplateToken.Kind.LongName, position, longValue, $"--{longValue}"); + break; } - var shortValue = ReadOptionName(buffer); - return new TemplateToken(TemplateToken.Kind.ShortName, position, shortValue, $"-{shortValue}"); - } - - private static string ReadOptionName(TextBuffer buffer) - { - var builder = new StringBuilder(); - while (!buffer.ReachedEnd) - { - var character = buffer.Peek(); - if (char.IsWhiteSpace(character) || character == '|') - { - break; - } - - builder.Append(buffer.Read()); - } - - return builder.ToString(); - } - - private static TemplateToken ReadValue(TextBuffer buffer, bool required) - { - var start = required ? '<' : '['; - var end = required ? '>' : ']'; - - var position = buffer.Position; - var kind = required ? TemplateToken.Kind.RequiredValue : TemplateToken.Kind.OptionalValue; - - // Consume start of value character (< or [). - buffer.Consume(start); - - var builder = new StringBuilder(); - while (!buffer.ReachedEnd) - { - var character = buffer.Peek(); - if (character == end) - { - break; - } - - buffer.Read(); - builder.Append(character); - } - - if (buffer.ReachedEnd) - { - var name = builder.ToString(); - var token = new TemplateToken(kind, position, name, $"{start}{name}"); - throw CommandTemplateException.UnterminatedValueName(buffer.Original, token); - } - - // Consume end of value character (> or ]). - buffer.Consume(end); - - // Get the value (the text within the brackets). - var value = builder.ToString(); - - // Create a token and return it. - return new TemplateToken(kind, position, value, required ? $"<{value}>" : $"[{value}]"); + buffer.Read(); } } + + private static TemplateToken ReadOption(TextBuffer buffer) + { + var position = buffer.Position; + + buffer.Consume('-'); + if (buffer.IsNext('-')) + { + buffer.Consume('-'); + var longValue = ReadOptionName(buffer); + return new TemplateToken(TemplateToken.Kind.LongName, position, longValue, $"--{longValue}"); + } + + var shortValue = ReadOptionName(buffer); + return new TemplateToken(TemplateToken.Kind.ShortName, position, shortValue, $"-{shortValue}"); + } + + private static string ReadOptionName(TextBuffer buffer) + { + var builder = new StringBuilder(); + while (!buffer.ReachedEnd) + { + var character = buffer.Peek(); + if (char.IsWhiteSpace(character) || character == '|') + { + break; + } + + builder.Append(buffer.Read()); + } + + return builder.ToString(); + } + + private static TemplateToken ReadValue(TextBuffer buffer, bool required) + { + var start = required ? '<' : '['; + var end = required ? '>' : ']'; + + var position = buffer.Position; + var kind = required ? TemplateToken.Kind.RequiredValue : TemplateToken.Kind.OptionalValue; + + // Consume start of value character (< or [). + buffer.Consume(start); + + var builder = new StringBuilder(); + while (!buffer.ReachedEnd) + { + var character = buffer.Peek(); + if (character == end) + { + break; + } + + buffer.Read(); + builder.Append(character); + } + + if (buffer.ReachedEnd) + { + var name = builder.ToString(); + var token = new TemplateToken(kind, position, name, $"{start}{name}"); + throw CommandTemplateException.UnterminatedValueName(buffer.Original, token); + } + + // Consume end of value character (> or ]). + buffer.Consume(end); + + // Get the value (the text within the brackets). + var value = builder.ToString(); + + // Create a token and return it. + return new TemplateToken(kind, position, value, required ? $"<{value}>" : $"[{value}]"); + } } \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Constants.cs b/src/Spectre.Console/Cli/Internal/Constants.cs index f7cb115..2edb189 100644 --- a/src/Spectre.Console/Cli/Internal/Constants.cs +++ b/src/Spectre.Console/Cli/Internal/Constants.cs @@ -1,23 +1,22 @@ -namespace Spectre.Console.Cli -{ - internal static class CliConstants - { - public const string DefaultCommandName = "__default_command"; - public const string True = "true"; - public const string False = "false"; +namespace Spectre.Console.Cli; - public static string[] AcceptedBooleanValues { get; } = new string[] - { +internal static class CliConstants +{ + public const string DefaultCommandName = "__default_command"; + public const string True = "true"; + public const string False = "false"; + + public static string[] AcceptedBooleanValues { get; } = new string[] + { True, False, - }; + }; - public static class Commands - { - public const string Branch = "cli"; - public const string Version = "version"; - public const string XmlDoc = "xmldoc"; - public const string Explain = "explain"; - } + public static class Commands + { + public const string Branch = "cli"; + public const string Version = "version"; + public const string XmlDoc = "xmldoc"; + public const string Explain = "explain"; } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/DefaultPairDeconstructor.cs b/src/Spectre.Console/Cli/Internal/DefaultPairDeconstructor.cs index 86b8f48..375c686 100644 --- a/src/Spectre.Console/Cli/Internal/DefaultPairDeconstructor.cs +++ b/src/Spectre.Console/Cli/Internal/DefaultPairDeconstructor.cs @@ -2,75 +2,74 @@ using System; using System.ComponentModel; using System.Diagnostics.CodeAnalysis; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +[SuppressMessage("Performance", "CA1812: Avoid uninstantiated internal classes")] +internal sealed class DefaultPairDeconstructor : IPairDeconstructor { - [SuppressMessage("Performance", "CA1812: Avoid uninstantiated internal classes")] - internal sealed class DefaultPairDeconstructor : IPairDeconstructor + /// + (object? Key, object? Value) IPairDeconstructor.Deconstruct( + ITypeResolver resolver, + Type keyType, + Type valueType, + string? value) { - /// - (object? Key, object? Value) IPairDeconstructor.Deconstruct( - ITypeResolver resolver, - Type keyType, - Type valueType, - string? value) + if (value == null) { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - var parts = value.Split(new[] { '=' }, StringSplitOptions.None); - if (parts.Length < 1 || parts.Length > 2) - { - throw CommandParseException.ValueIsNotInValidFormat(value); - } - - var stringkey = parts[0]; - var stringValue = parts.Length == 2 ? parts[1] : null; - if (stringValue == null) - { - // Got a default constructor? - if (valueType.IsValueType) - { - // Get the string variant of a default instance. - // Should not get null here, but compiler doesn't know that. - stringValue = Activator.CreateInstance(valueType)?.ToString() ?? string.Empty; - } - else - { - // Try with an empty string. - // Hopefully, the type converter knows how to convert it. - stringValue = string.Empty; - } - } - - return (Parse(stringkey, keyType), - Parse(stringValue, valueType)); + throw new ArgumentNullException(nameof(value)); } - private static object? Parse(string value, Type targetType) + var parts = value.Split(new[] { '=' }, StringSplitOptions.None); + if (parts.Length < 1 || parts.Length > 2) { - try + throw CommandParseException.ValueIsNotInValidFormat(value); + } + + var stringkey = parts[0]; + var stringValue = parts.Length == 2 ? parts[1] : null; + if (stringValue == null) + { + // Got a default constructor? + if (valueType.IsValueType) { - var converter = GetConverter(targetType); - return converter.ConvertFrom(value); + // Get the string variant of a default instance. + // Should not get null here, but compiler doesn't know that. + stringValue = Activator.CreateInstance(valueType)?.ToString() ?? string.Empty; } - catch + else { - // Can't convert something. Just give up and tell the user. - throw CommandParseException.ValueIsNotInValidFormat(value); + // Try with an empty string. + // Hopefully, the type converter knows how to convert it. + stringValue = string.Empty; } } - private static TypeConverter GetConverter(Type type) - { - var converter = TypeDescriptor.GetConverter(type); - if (converter != null) - { - return converter; - } + return (Parse(stringkey, keyType), + Parse(stringValue, valueType)); + } - throw new CommandConfigurationException($"Could find a type converter for '{type.FullName}'."); + private static object? Parse(string value, Type targetType) + { + try + { + var converter = GetConverter(targetType); + return converter.ConvertFrom(value); + } + catch + { + // Can't convert something. Just give up and tell the user. + throw CommandParseException.ValueIsNotInValidFormat(value); } } -} + + private static TypeConverter GetConverter(Type type) + { + var converter = TypeDescriptor.GetConverter(type); + if (converter != null) + { + return converter; + } + + throw new CommandConfigurationException($"Could find a type converter for '{type.FullName}'."); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/DelegateCommand.cs b/src/Spectre.Console/Cli/Internal/DelegateCommand.cs index 23cb7a7..44f3b8c 100644 --- a/src/Spectre.Console/Cli/Internal/DelegateCommand.cs +++ b/src/Spectre.Console/Cli/Internal/DelegateCommand.cs @@ -1,25 +1,24 @@ using System; using System.Threading.Tasks; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal sealed class DelegateCommand : ICommand { - internal sealed class DelegateCommand : ICommand + private readonly Func _func; + + public DelegateCommand(Func func) { - private readonly Func _func; - - public DelegateCommand(Func func) - { - _func = func; - } - - public Task Execute(CommandContext context, CommandSettings settings) - { - return Task.FromResult(_func(context, settings)); - } - - public ValidationResult Validate(CommandContext context, CommandSettings settings) - { - return ValidationResult.Success(); - } + _func = func; } -} + + public Task Execute(CommandContext context, CommandSettings settings) + { + return Task.FromResult(_func(context, settings)); + } + + public ValidationResult Validate(CommandContext context, CommandSettings settings) + { + return ValidationResult.Success(); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Exceptions/CommandLineParseExceptionFactory.cs b/src/Spectre.Console/Cli/Internal/Exceptions/CommandLineParseExceptionFactory.cs index a9902ac..a216d88 100644 --- a/src/Spectre.Console/Cli/Internal/Exceptions/CommandLineParseExceptionFactory.cs +++ b/src/Spectre.Console/Cli/Internal/Exceptions/CommandLineParseExceptionFactory.cs @@ -1,52 +1,51 @@ using System.Collections.Generic; using Spectre.Console.Rendering; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal static class CommandLineParseExceptionFactory { - internal static class CommandLineParseExceptionFactory + internal static CommandParseException Create(string arguments, CommandTreeToken token, string message, string details) { - internal static CommandParseException Create(string arguments, CommandTreeToken token, string message, string details) - { - return new CommandParseException(message, CreatePrettyMessage(arguments, token, message, details)); - } - - internal static CommandParseException Create(IEnumerable arguments, CommandTreeToken token, string message, string details) - { - return new CommandParseException(message, CreatePrettyMessage(string.Join(" ", arguments), token, message, details)); - } - - private static IRenderable CreatePrettyMessage(string arguments, CommandTreeToken token, string message, string details) - { - var composer = new Composer(); - - var position = token?.Position ?? 0; - var value = token?.Representation ?? arguments; - - // Header - composer.LineBreak(); - composer.Style("red", "Error:"); - composer.Space().Text(message.EscapeMarkup()); - composer.LineBreak(); - - // Template - composer.LineBreak(); - composer.Spaces(7).Text(arguments.EscapeMarkup()); - - // Error - composer.LineBreak(); - composer.Spaces(7).Spaces(position); - - composer.Style("red", error => - { - error.Repeat('^', value.Length); - error.Space(); - error.Text(details.TrimEnd('.').EscapeMarkup()); - error.LineBreak(); - }); - - composer.LineBreak(); - - return composer; - } + return new CommandParseException(message, CreatePrettyMessage(arguments, token, message, details)); } -} + + internal static CommandParseException Create(IEnumerable arguments, CommandTreeToken token, string message, string details) + { + return new CommandParseException(message, CreatePrettyMessage(string.Join(" ", arguments), token, message, details)); + } + + private static IRenderable CreatePrettyMessage(string arguments, CommandTreeToken token, string message, string details) + { + var composer = new Composer(); + + var position = token?.Position ?? 0; + var value = token?.Representation ?? arguments; + + // Header + composer.LineBreak(); + composer.Style("red", "Error:"); + composer.Space().Text(message.EscapeMarkup()); + composer.LineBreak(); + + // Template + composer.LineBreak(); + composer.Spaces(7).Text(arguments.EscapeMarkup()); + + // Error + composer.LineBreak(); + composer.Spaces(7).Spaces(position); + + composer.Style("red", error => + { + error.Repeat('^', value.Length); + error.Space(); + error.Text(details.TrimEnd('.').EscapeMarkup()); + error.LineBreak(); + }); + + composer.LineBreak(); + + return composer; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Exceptions/CommandLineTemplateExceptionFactory.cs b/src/Spectre.Console/Cli/Internal/Exceptions/CommandLineTemplateExceptionFactory.cs index 4ce00d5..14c1ee0 100644 --- a/src/Spectre.Console/Cli/Internal/Exceptions/CommandLineTemplateExceptionFactory.cs +++ b/src/Spectre.Console/Cli/Internal/Exceptions/CommandLineTemplateExceptionFactory.cs @@ -1,57 +1,56 @@ using Spectre.Console.Rendering; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal static class CommandLineTemplateExceptionFactory { - internal static class CommandLineTemplateExceptionFactory + internal static CommandTemplateException Create(string template, TemplateToken? token, string message, string details) { - internal static CommandTemplateException Create(string template, TemplateToken? token, string message, string details) - { - return new CommandTemplateException(message, template, CreatePrettyMessage(template, token, message, details)); - } - - private static IRenderable CreatePrettyMessage(string template, TemplateToken? token, string message, string details) - { - var composer = new Composer(); - - var position = token?.Position ?? 0; - var value = token?.Representation ?? template; - - // Header - composer.LineBreak(); - composer.Style("red", "Error:"); - composer.Space().Text("An error occured when parsing template."); - composer.LineBreak(); - composer.Spaces(7).Style("yellow", message.EscapeMarkup()); - composer.LineBreak(); - - if (string.IsNullOrWhiteSpace(template)) - { - // Error - composer.LineBreak(); - composer.Style("red", message.EscapeMarkup()); - composer.LineBreak(); - } - else - { - // Template - composer.LineBreak(); - composer.Spaces(7).Text(template.EscapeMarkup()); - - // Error - composer.LineBreak(); - composer.Spaces(7).Spaces(position); - composer.Style("red", error => - { - error.Repeat('^', value.Length); - error.Space(); - error.Text(details.TrimEnd('.').EscapeMarkup()); - error.LineBreak(); - }); - } - - composer.LineBreak(); - - return composer; - } + return new CommandTemplateException(message, template, CreatePrettyMessage(template, token, message, details)); } -} + + private static IRenderable CreatePrettyMessage(string template, TemplateToken? token, string message, string details) + { + var composer = new Composer(); + + var position = token?.Position ?? 0; + var value = token?.Representation ?? template; + + // Header + composer.LineBreak(); + composer.Style("red", "Error:"); + composer.Space().Text("An error occured when parsing template."); + composer.LineBreak(); + composer.Spaces(7).Style("yellow", message.EscapeMarkup()); + composer.LineBreak(); + + if (string.IsNullOrWhiteSpace(template)) + { + // Error + composer.LineBreak(); + composer.Style("red", message.EscapeMarkup()); + composer.LineBreak(); + } + else + { + // Template + composer.LineBreak(); + composer.Spaces(7).Text(template.EscapeMarkup()); + + // Error + composer.LineBreak(); + composer.Spaces(7).Spaces(position); + composer.Style("red", error => + { + error.Repeat('^', value.Length); + error.Space(); + error.Text(details.TrimEnd('.').EscapeMarkup()); + error.LineBreak(); + }); + } + + composer.LineBreak(); + + return composer; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Extensions/AnsiConsoleExtensions.cs b/src/Spectre.Console/Cli/Internal/Extensions/AnsiConsoleExtensions.cs index 2d96925..8125625 100644 --- a/src/Spectre.Console/Cli/Internal/Extensions/AnsiConsoleExtensions.cs +++ b/src/Spectre.Console/Cli/Internal/Extensions/AnsiConsoleExtensions.cs @@ -2,41 +2,40 @@ using System; using System.Collections.Generic; using Spectre.Console.Rendering; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal static class AnsiConsoleExtensions { - internal static class AnsiConsoleExtensions + private static readonly Lazy _console; + + static AnsiConsoleExtensions() { - private static readonly Lazy _console; + _console = new Lazy(() => AnsiConsole.Console); + } - static AnsiConsoleExtensions() + public static IAnsiConsole GetConsole(this IAnsiConsole? console) + { + return console ?? _console.Value; + } + + public static void SafeRender(this IAnsiConsole? console, IRenderable? renderable) + { + if (renderable != null) { - _console = new Lazy(() => AnsiConsole.Console); + console ??= _console.Value; + console.Write(renderable); } + } - public static IAnsiConsole GetConsole(this IAnsiConsole? console) - { - return console ?? _console.Value; - } - - public static void SafeRender(this IAnsiConsole? console, IRenderable? renderable) + public static void SafeRender(this IAnsiConsole? console, IEnumerable renderables) + { + console ??= _console.Value; + foreach (var renderable in renderables) { if (renderable != null) { - console ??= _console.Value; console.Write(renderable); } } - - public static void SafeRender(this IAnsiConsole? console, IEnumerable renderables) - { - console ??= _console.Value; - foreach (var renderable in renderables) - { - if (renderable != null) - { - console.Write(renderable); - } - } - } } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Extensions/CaseSensitivityExtensions.cs b/src/Spectre.Console/Cli/Internal/Extensions/CaseSensitivityExtensions.cs index 9ce2814..4b8101d 100644 --- a/src/Spectre.Console/Cli/Internal/Extensions/CaseSensitivityExtensions.cs +++ b/src/Spectre.Console/Cli/Internal/Extensions/CaseSensitivityExtensions.cs @@ -1,35 +1,34 @@ using System; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal static class CaseSensitivityExtensions { - internal static class CaseSensitivityExtensions + public static StringComparison GetStringComparison(this CaseSensitivity caseSensitivity, CommandPart part) { - public static StringComparison GetStringComparison(this CaseSensitivity caseSensitivity, CommandPart part) + if (part == CommandPart.CommandName && (caseSensitivity & CaseSensitivity.Commands) == 0) { - if (part == CommandPart.CommandName && (caseSensitivity & CaseSensitivity.Commands) == 0) - { - return StringComparison.OrdinalIgnoreCase; - } - else if (part == CommandPart.LongOption && (caseSensitivity & CaseSensitivity.LongOptions) == 0) - { - return StringComparison.OrdinalIgnoreCase; - } - - return StringComparison.Ordinal; + return StringComparison.OrdinalIgnoreCase; + } + else if (part == CommandPart.LongOption && (caseSensitivity & CaseSensitivity.LongOptions) == 0) + { + return StringComparison.OrdinalIgnoreCase; } - public static StringComparer GetStringComparer(this CaseSensitivity caseSensitivity, CommandPart part) - { - if (part == CommandPart.CommandName && (caseSensitivity & CaseSensitivity.Commands) == 0) - { - return StringComparer.OrdinalIgnoreCase; - } - else if (part == CommandPart.LongOption && (caseSensitivity & CaseSensitivity.LongOptions) == 0) - { - return StringComparer.OrdinalIgnoreCase; - } - - return StringComparer.Ordinal; - } + return StringComparison.Ordinal; } -} + + public static StringComparer GetStringComparer(this CaseSensitivity caseSensitivity, CommandPart part) + { + if (part == CommandPart.CommandName && (caseSensitivity & CaseSensitivity.Commands) == 0) + { + return StringComparer.OrdinalIgnoreCase; + } + else if (part == CommandPart.LongOption && (caseSensitivity & CaseSensitivity.LongOptions) == 0) + { + return StringComparer.OrdinalIgnoreCase; + } + + return StringComparer.Ordinal; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Extensions/ListExtensions.cs b/src/Spectre.Console/Cli/Internal/Extensions/ListExtensions.cs index c9f22ae..996c9cc 100644 --- a/src/Spectre.Console/Cli/Internal/Extensions/ListExtensions.cs +++ b/src/Spectre.Console/Cli/Internal/Extensions/ListExtensions.cs @@ -1,55 +1,54 @@ using System; using System.Collections.Generic; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal static class ListExtensions { - internal static class ListExtensions + public static void ForEach(this IEnumerable source, Action action) { - public static void ForEach(this IEnumerable source, Action action) + if (source != null && action != null) { - if (source != null && action != null) + foreach (var item in source) { - foreach (var item in source) - { - action(item); - } + action(item); } } + } - public static T AddAndReturn(this IList source, T item) - where T : class + public static T AddAndReturn(this IList source, T item) + where T : class + { + source.Add(item); + return item; + } + + public static void AddIfNotNull(this IList source, T? item) + where T : class + { + if (item != null) { source.Add(item); - return item; } + } - public static void AddIfNotNull(this IList source, T? item) - where T : class + public static void AddRangeIfNotNull(this IList source, IEnumerable items) + where T : class + { + foreach (var item in items) { if (item != null) { source.Add(item); } } + } - public static void AddRangeIfNotNull(this IList source, IEnumerable items) - where T : class + public static void AddRange(this IList source, IEnumerable items) + { + foreach (var item in items) { - foreach (var item in items) - { - if (item != null) - { - source.Add(item); - } - } - } - - public static void AddRange(this IList source, IEnumerable items) - { - foreach (var item in items) - { - source.Add(item); - } + source.Add(item); } } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Extensions/StringExtensions.cs b/src/Spectre.Console/Cli/Internal/Extensions/StringExtensions.cs index 44fa917..2119e10 100644 --- a/src/Spectre.Console/Cli/Internal/Extensions/StringExtensions.cs +++ b/src/Spectre.Console/Cli/Internal/Extensions/StringExtensions.cs @@ -1,14 +1,13 @@ -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal static class StringExtensions { - internal static class StringExtensions + internal static int OrdinalIndexOf(this string text, char token) { - internal static int OrdinalIndexOf(this string text, char token) - { #if NETSTANDARD2_0 - return text.IndexOf(token); + return text.IndexOf(token); #else - return text.IndexOf(token, System.StringComparison.Ordinal); + return text.IndexOf(token, System.StringComparison.Ordinal); #endif - } } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Extensions/TypeExtensions.cs b/src/Spectre.Console/Cli/Internal/Extensions/TypeExtensions.cs index 1eb500b..f416065 100644 --- a/src/Spectre.Console/Cli/Internal/Extensions/TypeExtensions.cs +++ b/src/Spectre.Console/Cli/Internal/Extensions/TypeExtensions.cs @@ -2,23 +2,22 @@ using System; using System.Collections.Generic; using System.Linq; -namespace Spectre.Console.Cli -{ - internal static class TypeExtensions - { - public static bool IsPairDeconstructable(this Type type) - { - if (type.IsGenericType) - { - if (type.GetGenericTypeDefinition() == typeof(ILookup<,>) || - type.GetGenericTypeDefinition() == typeof(IDictionary<,>) || - type.GetGenericTypeDefinition() == typeof(IReadOnlyDictionary<,>)) - { - return true; - } - } +namespace Spectre.Console.Cli; - return false; +internal static class TypeExtensions +{ + public static bool IsPairDeconstructable(this Type type) + { + if (type.IsGenericType) + { + if (type.GetGenericTypeDefinition() == typeof(ILookup<,>) || + type.GetGenericTypeDefinition() == typeof(IDictionary<,>) || + type.GetGenericTypeDefinition() == typeof(IReadOnlyDictionary<,>)) + { + return true; + } } + + return false; } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Extensions/TypeRegistrarExtensions.cs b/src/Spectre.Console/Cli/Internal/Extensions/TypeRegistrarExtensions.cs index 4b73fb5..d445fd1 100644 --- a/src/Spectre.Console/Cli/Internal/Extensions/TypeRegistrarExtensions.cs +++ b/src/Spectre.Console/Cli/Internal/Extensions/TypeRegistrarExtensions.cs @@ -2,56 +2,55 @@ using System; using System.Collections.Generic; using System.Diagnostics; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal static class TypeRegistrarExtensions { - internal static class TypeRegistrarExtensions + public static void RegisterDependencies(this ITypeRegistrar registrar, CommandModel model) { - public static void RegisterDependencies(this ITypeRegistrar registrar, CommandModel model) + var stack = new Stack(); + model.Commands.ForEach(c => stack.Push(c)); + if (model.DefaultCommand != null) { - var stack = new Stack(); - model.Commands.ForEach(c => stack.Push(c)); - if (model.DefaultCommand != null) + stack.Push(model.DefaultCommand); + } + + while (stack.Count > 0) + { + var command = stack.Pop(); + + if (command.SettingsType == null) { - stack.Push(model.DefaultCommand); + // TODO: Error message + throw new InvalidOperationException("Command setting type cannot be null."); } - while (stack.Count > 0) + if (command.CommandType != null) { - var command = stack.Pop(); + registrar?.Register(command.CommandType, command.CommandType); + } - if (command.SettingsType == null) + foreach (var parameter in command.Parameters) + { + var pairDeconstructor = parameter?.PairDeconstructor?.Type; + if (pairDeconstructor != null) { - // TODO: Error message - throw new InvalidOperationException("Command setting type cannot be null."); + registrar?.Register(pairDeconstructor, pairDeconstructor); } - if (command.CommandType != null) + var typeConverterTypeName = parameter?.Converter?.ConverterTypeName; + if (!string.IsNullOrWhiteSpace(typeConverterTypeName)) { - registrar?.Register(command.CommandType, command.CommandType); + var typeConverterType = Type.GetType(typeConverterTypeName); + Debug.Assert(typeConverterType != null, "Could not create type"); + registrar?.Register(typeConverterType, typeConverterType); } + } - foreach (var parameter in command.Parameters) - { - var pairDeconstructor = parameter?.PairDeconstructor?.Type; - if (pairDeconstructor != null) - { - registrar?.Register(pairDeconstructor, pairDeconstructor); - } - - var typeConverterTypeName = parameter?.Converter?.ConverterTypeName; - if (!string.IsNullOrWhiteSpace(typeConverterTypeName)) - { - var typeConverterType = Type.GetType(typeConverterTypeName); - Debug.Assert(typeConverterType != null, "Could not create type"); - registrar?.Register(typeConverterType, typeConverterType); - } - } - - foreach (var child in command.Children) - { - stack.Push(child); - } + foreach (var child in command.Children) + { + stack.Push(child); } } } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Extensions/XmlElementExtensions.cs b/src/Spectre.Console/Cli/Internal/Extensions/XmlElementExtensions.cs index 1eaa098..4fe8d51 100644 --- a/src/Spectre.Console/Cli/Internal/Extensions/XmlElementExtensions.cs +++ b/src/Spectre.Console/Cli/Internal/Extensions/XmlElementExtensions.cs @@ -5,43 +5,42 @@ using System.Linq; using System.Reflection; using System.Xml; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal static class XmlElementExtensions { - internal static class XmlElementExtensions + public static void SetNullableAttribute(this XmlElement element, string name, string? value) { - public static void SetNullableAttribute(this XmlElement element, string name, string? value) + element.SetAttribute(name, value ?? "NULL"); + } + + public static void SetNullableAttribute(this XmlElement element, string name, IEnumerable? values) + { + if (values?.Any() != true) { - element.SetAttribute(name, value ?? "NULL"); + element.SetAttribute(name, "NULL"); } - public static void SetNullableAttribute(this XmlElement element, string name, IEnumerable? values) + element.SetAttribute(name, string.Join(",", values ?? Enumerable.Empty())); + } + + public static void SetBooleanAttribute(this XmlElement element, string name, bool value) + { + element.SetAttribute(name, value ? "true" : "false"); + } + + public static void SetEnumAttribute(this XmlElement element, string name, Enum value) + { + var field = value.GetType().GetField(value.ToString()); + if (field != null) { - if (values?.Any() != true) + var attribute = field.GetCustomAttribute(false); + if (attribute == null) { - element.SetAttribute(name, "NULL"); + throw new InvalidOperationException("Enum is missing description."); } - element.SetAttribute(name, string.Join(",", values ?? Enumerable.Empty())); - } - - public static void SetBooleanAttribute(this XmlElement element, string name, bool value) - { - element.SetAttribute(name, value ? "true" : "false"); - } - - public static void SetEnumAttribute(this XmlElement element, string name, Enum value) - { - var field = value.GetType().GetField(value.ToString()); - if (field != null) - { - var attribute = field.GetCustomAttribute(false); - if (attribute == null) - { - throw new InvalidOperationException("Enum is missing description."); - } - - element.SetAttribute(name, attribute.Description); - } + element.SetAttribute(name, attribute.Description); } } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/HelpWriter.cs b/src/Spectre.Console/Cli/Internal/HelpWriter.cs index fe38eaa..353c0e8 100644 --- a/src/Spectre.Console/Cli/Internal/HelpWriter.cs +++ b/src/Spectre.Console/Cli/Internal/HelpWriter.cs @@ -4,377 +4,376 @@ using System.Linq; using System.Text; using Spectre.Console.Rendering; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal static class HelpWriter { - internal static class HelpWriter + private sealed class HelpArgument { - private sealed class HelpArgument + public string Name { get; } + public int Position { get; set; } + public bool Required { get; } + public string? Description { get; } + + public HelpArgument(string name, int position, bool required, string? description) { - public string Name { get; } - public int Position { get; set; } - public bool Required { get; } - public string? Description { get; } - - public HelpArgument(string name, int position, bool required, string? description) - { - Name = name; - Position = position; - Required = required; - Description = description; - } - - public static IReadOnlyList Get(CommandInfo? command) - { - var arguments = new List(); - arguments.AddRange(command?.Parameters?.OfType()?.Select( - x => new HelpArgument(x.Value, x.Position, x.Required, x.Description)) - ?? Array.Empty()); - return arguments; - } + Name = name; + Position = position; + Required = required; + Description = description; } - private sealed class HelpOption + public static IReadOnlyList Get(CommandInfo? command) { - public string Short { get; } - public string Long { get; } - public string? Value { get; } - public bool? ValueIsOptional { get; } - public string? Description { get; } + var arguments = new List(); + arguments.AddRange(command?.Parameters?.OfType()?.Select( + x => new HelpArgument(x.Value, x.Position, x.Required, x.Description)) + ?? Array.Empty()); + return arguments; + } + } - public HelpOption(string @short, string @long, string? @value, bool? valueIsOptional, string? description) + private sealed class HelpOption + { + public string Short { get; } + public string Long { get; } + public string? Value { get; } + public bool? ValueIsOptional { get; } + public string? Description { get; } + + public HelpOption(string @short, string @long, string? @value, bool? valueIsOptional, string? description) + { + Short = @short; + Long = @long; + Value = value; + ValueIsOptional = valueIsOptional; + Description = description; + } + + public static IReadOnlyList Get(CommandModel model, CommandInfo? command) + { + var parameters = new List(); + parameters.Add(new HelpOption("h", "help", null, null, "Prints help information")); + + // At the root and no default command? + if (command == null && model?.DefaultCommand == null) { - Short = @short; - Long = @long; - Value = value; - ValueIsOptional = valueIsOptional; - Description = description; + parameters.Add(new HelpOption("v", "version", null, null, "Prints version information")); } - public static IReadOnlyList Get(CommandModel model, CommandInfo? command) - { - var parameters = new List(); - parameters.Add(new HelpOption("h", "help", null, null, "Prints help information")); + parameters.AddRange(command?.Parameters.OfType().Where(o => !o.IsHidden).Select(o => + new HelpOption( + o.ShortNames.FirstOrDefault(), o.LongNames.FirstOrDefault(), + o.ValueName, o.ValueIsOptional, o.Description)) + ?? Array.Empty()); + return parameters; + } + } - // At the root and no default command? - if (command == null && model?.DefaultCommand == null) + public static IEnumerable Write(CommandModel model) + { + return WriteCommand(model, null); + } + + public static IEnumerable WriteCommand(CommandModel model, CommandInfo? command) + { + var container = command as ICommandContainer ?? model; + var isDefaultCommand = command?.IsDefaultCommand ?? false; + + var result = new List(); + result.AddRange(GetUsage(model, command)); + result.AddRange(GetExamples(model, command)); + result.AddRange(GetArguments(command)); + result.AddRange(GetOptions(model, command)); + result.AddRange(GetCommands(model, container, isDefaultCommand)); + + return result; + } + + private static IEnumerable GetUsage(CommandModel model, CommandInfo? command) + { + var composer = new Composer(); + composer.Style("yellow", "USAGE:").LineBreak(); + composer.Tab().Text(model.GetApplicationName()); + + var parameters = new List(); + + if (command == null) + { + parameters.Add("[grey][[OPTIONS]][/]"); + parameters.Add("[aqua][/]"); + } + else + { + foreach (var current in command.Flatten()) + { + var isCurrent = current == command; + + if (!current.IsDefaultCommand) { - parameters.Add(new HelpOption("v", "version", null, null, "Prints version information")); - } - - parameters.AddRange(command?.Parameters.OfType().Where(o => !o.IsHidden).Select(o => - new HelpOption( - o.ShortNames.FirstOrDefault(), o.LongNames.FirstOrDefault(), - o.ValueName, o.ValueIsOptional, o.Description)) - ?? Array.Empty()); - return parameters; - } - } - - public static IEnumerable Write(CommandModel model) - { - return WriteCommand(model, null); - } - - public static IEnumerable WriteCommand(CommandModel model, CommandInfo? command) - { - var container = command as ICommandContainer ?? model; - var isDefaultCommand = command?.IsDefaultCommand ?? false; - - var result = new List(); - result.AddRange(GetUsage(model, command)); - result.AddRange(GetExamples(model, command)); - result.AddRange(GetArguments(command)); - result.AddRange(GetOptions(model, command)); - result.AddRange(GetCommands(model, container, isDefaultCommand)); - - return result; - } - - private static IEnumerable GetUsage(CommandModel model, CommandInfo? command) - { - var composer = new Composer(); - composer.Style("yellow", "USAGE:").LineBreak(); - composer.Tab().Text(model.GetApplicationName()); - - var parameters = new List(); - - if (command == null) - { - parameters.Add("[grey][[OPTIONS]][/]"); - parameters.Add("[aqua][/]"); - } - else - { - foreach (var current in command.Flatten()) - { - var isCurrent = current == command; - - if (!current.IsDefaultCommand) - { - if (isCurrent) - { - parameters.Add($"[underline]{current.Name.EscapeMarkup()}[/]"); - } - else - { - parameters.Add($"{current.Name.EscapeMarkup()}"); - } - } - - if (current.Parameters.OfType().Any()) - { - if (isCurrent) - { - foreach (var argument in current.Parameters.OfType() - .Where(a => a.Required).OrderBy(a => a.Position).ToArray()) - { - parameters.Add($"[aqua]<{argument.Value.EscapeMarkup()}>[/]"); - } - } - - var optionalArguments = current.Parameters.OfType().Where(x => !x.Required).ToArray(); - if (optionalArguments.Length > 0 || !isCurrent) - { - foreach (var optionalArgument in optionalArguments) - { - parameters.Add($"[silver][[{optionalArgument.Value.EscapeMarkup()}]][/]"); - } - } - } - if (isCurrent) { - parameters.Add("[grey][[OPTIONS]][/]"); + parameters.Add($"[underline]{current.Name.EscapeMarkup()}[/]"); + } + else + { + parameters.Add($"{current.Name.EscapeMarkup()}"); } } - if (command.IsBranch) + if (current.Parameters.OfType().Any()) { - parameters.Add("[aqua][/]"); + if (isCurrent) + { + foreach (var argument in current.Parameters.OfType() + .Where(a => a.Required).OrderBy(a => a.Position).ToArray()) + { + parameters.Add($"[aqua]<{argument.Value.EscapeMarkup()}>[/]"); + } + } + + var optionalArguments = current.Parameters.OfType().Where(x => !x.Required).ToArray(); + if (optionalArguments.Length > 0 || !isCurrent) + { + foreach (var optionalArgument in optionalArguments) + { + parameters.Add($"[silver][[{optionalArgument.Value.EscapeMarkup()}]][/]"); + } + } + } + + if (isCurrent) + { + parameters.Add("[grey][[OPTIONS]][/]"); } } - composer.Join(" ", parameters); - composer.LineBreak(); - - return new[] + if (command.IsBranch) { - composer, - }; + parameters.Add("[aqua][/]"); + } } - private static IEnumerable GetExamples(CommandModel model, CommandInfo? command) + composer.Join(" ", parameters); + composer.LineBreak(); + + return new[] { - var maxExamples = int.MaxValue; + composer, + }; + } - var examples = command?.Examples ?? model.Examples ?? new List(); - if (examples.Count == 0) + private static IEnumerable GetExamples(CommandModel model, CommandInfo? command) + { + var maxExamples = int.MaxValue; + + var examples = command?.Examples ?? model.Examples ?? new List(); + if (examples.Count == 0) + { + // Since we're not checking direct examples, + // make sure that we limit the number of examples. + maxExamples = 5; + + // Get the current root command. + var root = command ?? (ICommandContainer)model; + var queue = new Queue(new[] { root }); + + // Traverse the command tree and look for examples. + // As soon as a node contains commands, bail. + while (queue.Count > 0) { - // Since we're not checking direct examples, - // make sure that we limit the number of examples. - maxExamples = 5; + var current = queue.Dequeue(); - // Get the current root command. - var root = command ?? (ICommandContainer)model; - var queue = new Queue(new[] { root }); - - // Traverse the command tree and look for examples. - // As soon as a node contains commands, bail. - while (queue.Count > 0) + foreach (var cmd in current.Commands.Where(x => !x.IsHidden)) { - var current = queue.Dequeue(); - - foreach (var cmd in current.Commands.Where(x => !x.IsHidden)) + if (cmd.Examples.Count > 0) { - if (cmd.Examples.Count > 0) - { - examples.AddRange(cmd.Examples); - } - - queue.Enqueue(cmd); + examples.AddRange(cmd.Examples); } - if (examples.Count >= maxExamples) - { - break; - } + queue.Enqueue(cmd); + } + + if (examples.Count >= maxExamples) + { + break; } } + } - if (examples.Count > 0) + if (examples.Count > 0) + { + var composer = new Composer(); + composer.LineBreak(); + composer.Style("yellow", "EXAMPLES:").LineBreak(); + + for (var index = 0; index < Math.Min(maxExamples, examples.Count); index++) { - var composer = new Composer(); + var args = string.Join(" ", examples[index]); + composer.Tab().Text(model.GetApplicationName()).Space().Style("grey", args); composer.LineBreak(); - composer.Style("yellow", "EXAMPLES:").LineBreak(); - - for (var index = 0; index < Math.Min(maxExamples, examples.Count); index++) - { - var args = string.Join(" ", examples[index]); - composer.Tab().Text(model.GetApplicationName()).Space().Style("grey", args); - composer.LineBreak(); - } - - return new[] { composer }; } + return new[] { composer }; + } + + return Array.Empty(); + } + + private static IEnumerable GetArguments(CommandInfo? command) + { + var arguments = HelpArgument.Get(command); + if (arguments.Count == 0) + { return Array.Empty(); } - private static IEnumerable GetArguments(CommandInfo? command) - { - var arguments = HelpArgument.Get(command); - if (arguments.Count == 0) - { - return Array.Empty(); - } - - var result = new List + var result = new List { new Markup(Environment.NewLine), new Markup("[yellow]ARGUMENTS:[/]"), new Markup(Environment.NewLine), }; - var grid = new Grid(); - grid.AddColumn(new GridColumn { Padding = new Padding(4, 4), NoWrap = true }); - grid.AddColumn(new GridColumn { Padding = new Padding(0, 0) }); + var grid = new Grid(); + grid.AddColumn(new GridColumn { Padding = new Padding(4, 4), NoWrap = true }); + grid.AddColumn(new GridColumn { Padding = new Padding(0, 0) }); - foreach (var argument in arguments.Where(x => x.Required).OrderBy(x => x.Position)) - { - grid.AddRow( - $"[silver]<{argument.Name.EscapeMarkup()}>[/]", - argument.Description?.TrimEnd('.') ?? " "); - } - - foreach (var argument in arguments.Where(x => !x.Required).OrderBy(x => x.Position)) - { - grid.AddRow( - $"[grey][[{argument.Name.EscapeMarkup()}]][/]", - argument.Description?.TrimEnd('.') ?? " "); - } - - result.Add(grid); - - return result; + foreach (var argument in arguments.Where(x => x.Required).OrderBy(x => x.Position)) + { + grid.AddRow( + $"[silver]<{argument.Name.EscapeMarkup()}>[/]", + argument.Description?.TrimEnd('.') ?? " "); } - private static IEnumerable GetOptions(CommandModel model, CommandInfo? command) + foreach (var argument in arguments.Where(x => !x.Required).OrderBy(x => x.Position)) { - // Collect all options into a single structure. - var parameters = HelpOption.Get(model, command); - if (parameters.Count == 0) - { - return Array.Empty(); - } + grid.AddRow( + $"[grey][[{argument.Name.EscapeMarkup()}]][/]", + argument.Description?.TrimEnd('.') ?? " "); + } - var result = new List + result.Add(grid); + + return result; + } + + private static IEnumerable GetOptions(CommandModel model, CommandInfo? command) + { + // Collect all options into a single structure. + var parameters = HelpOption.Get(model, command); + if (parameters.Count == 0) + { + return Array.Empty(); + } + + var result = new List { new Markup(Environment.NewLine), new Markup("[yellow]OPTIONS:[/]"), new Markup(Environment.NewLine), }; - var grid = new Grid(); - grid.AddColumn(new GridColumn { Padding = new Padding(4, 4), NoWrap = true }); - grid.AddColumn(new GridColumn { Padding = new Padding(0, 0) }); + var grid = new Grid(); + grid.AddColumn(new GridColumn { Padding = new Padding(4, 4), NoWrap = true }); + grid.AddColumn(new GridColumn { Padding = new Padding(0, 0) }); - static string GetOptionParts(HelpOption option) + static string GetOptionParts(HelpOption option) + { + var builder = new StringBuilder(); + if (option.Short != null) { - var builder = new StringBuilder(); - if (option.Short != null) + builder.Append('-').Append(option.Short.EscapeMarkup()); + if (option.Long != null) { - builder.Append('-').Append(option.Short.EscapeMarkup()); - if (option.Long != null) - { - builder.Append(", "); - } + builder.Append(", "); + } + } + else + { + builder.Append(" "); + if (option.Long != null) + { + builder.Append(" "); + } + } + + if (option.Long != null) + { + builder.Append("--").Append(option.Long.EscapeMarkup()); + } + + if (option.Value != null) + { + builder.Append(' '); + if (option.ValueIsOptional ?? false) + { + builder.Append("[grey][[").Append(option.Value.EscapeMarkup()).Append("]][/]"); } else { - builder.Append(" "); - if (option.Long != null) - { - builder.Append(" "); - } + builder.Append("[silver]<").Append(option.Value.EscapeMarkup()).Append(">[/]"); } - - if (option.Long != null) - { - builder.Append("--").Append(option.Long.EscapeMarkup()); - } - - if (option.Value != null) - { - builder.Append(' '); - if (option.ValueIsOptional ?? false) - { - builder.Append("[grey][[").Append(option.Value.EscapeMarkup()).Append("]][/]"); - } - else - { - builder.Append("[silver]<").Append(option.Value.EscapeMarkup()).Append(">[/]"); - } - } - - return builder.ToString(); } - foreach (var option in parameters.ToArray()) - { - grid.AddRow( - GetOptionParts(option), - option.Description?.TrimEnd('.') ?? " "); - } - - result.Add(grid); - - return result; + return builder.ToString(); } - private static IEnumerable GetCommands( - CommandModel model, - ICommandContainer command, - bool isDefaultCommand) + foreach (var option in parameters.ToArray()) { - var commands = isDefaultCommand ? model.Commands : command.Commands; - commands = commands.Where(x => !x.IsHidden).ToList(); + grid.AddRow( + GetOptionParts(option), + option.Description?.TrimEnd('.') ?? " "); + } - if (commands.Count == 0) - { - return Array.Empty(); - } + result.Add(grid); - var result = new List + return result; + } + + private static IEnumerable GetCommands( + CommandModel model, + ICommandContainer command, + bool isDefaultCommand) + { + var commands = isDefaultCommand ? model.Commands : command.Commands; + commands = commands.Where(x => !x.IsHidden).ToList(); + + if (commands.Count == 0) + { + return Array.Empty(); + } + + var result = new List { new Markup(Environment.NewLine), new Markup("[yellow]COMMANDS:[/]"), new Markup(Environment.NewLine), }; - var grid = new Grid(); - grid.AddColumn(new GridColumn { Padding = new Padding(4, 4), NoWrap = true }); - grid.AddColumn(new GridColumn { Padding = new Padding(0, 0) }); + var grid = new Grid(); + grid.AddColumn(new GridColumn { Padding = new Padding(4, 4), NoWrap = true }); + grid.AddColumn(new GridColumn { Padding = new Padding(0, 0) }); - foreach (var child in commands) + foreach (var child in commands) + { + var arguments = new Composer(); + arguments.Style("silver", child.Name.EscapeMarkup()); + arguments.Space(); + + foreach (var argument in HelpArgument.Get(child).Where(a => a.Required)) { - var arguments = new Composer(); - arguments.Style("silver", child.Name.EscapeMarkup()); + arguments.Style("silver", $"<{argument.Name.EscapeMarkup()}>"); arguments.Space(); - - foreach (var argument in HelpArgument.Get(child).Where(a => a.Required)) - { - arguments.Style("silver", $"<{argument.Name.EscapeMarkup()}>"); - arguments.Space(); - } - - grid.AddRow( - arguments.ToString().TrimEnd(), - child.Description?.TrimEnd('.') ?? " "); } - result.Add(grid); - - return result; + grid.AddRow( + arguments.ToString().TrimEnd(), + child.Description?.TrimEnd('.') ?? " "); } + + result.Add(grid); + + return result; } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/IPairDeconstructor.cs b/src/Spectre.Console/Cli/Internal/IPairDeconstructor.cs index 2b5d383..9050694 100644 --- a/src/Spectre.Console/Cli/Internal/IPairDeconstructor.cs +++ b/src/Spectre.Console/Cli/Internal/IPairDeconstructor.cs @@ -1,24 +1,23 @@ using System; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// Represents a pair deconstructor. +/// +internal interface IPairDeconstructor { /// - /// Represents a pair deconstructor. + /// Deconstructs the specified value into its components. /// - internal interface IPairDeconstructor - { - /// - /// Deconstructs the specified value into its components. - /// - /// The type resolver to use. - /// The key type. - /// The value type. - /// The value to deconstruct. - /// A deconstructed value. - (object? Key, object? Value) Deconstruct( - ITypeResolver resolver, - Type keyType, - Type valueType, - string? value); - } -} + /// The type resolver to use. + /// The key type. + /// The value type. + /// The value to deconstruct. + /// A deconstructed value. + (object? Key, object? Value) Deconstruct( + ITypeResolver resolver, + Type keyType, + Type valueType, + string? value); +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Modelling/CommandArgument.cs b/src/Spectre.Console/Cli/Internal/Modelling/CommandArgument.cs index 9d71d4c..f6c265a 100644 --- a/src/Spectre.Console/Cli/Internal/Modelling/CommandArgument.cs +++ b/src/Spectre.Console/Cli/Internal/Modelling/CommandArgument.cs @@ -3,23 +3,22 @@ using System.Collections.Generic; using System.ComponentModel; using System.Reflection; -namespace Spectre.Console.Cli -{ - internal sealed class CommandArgument : CommandParameter - { - public string Value { get; } - public int Position { get; set; } +namespace Spectre.Console.Cli; - public CommandArgument( - Type parameterType, ParameterKind parameterKind, PropertyInfo property, string? description, - TypeConverterAttribute? converter, DefaultValueAttribute? defaultValue, - CommandArgumentAttribute argument, ParameterValueProviderAttribute? valueProvider, - IEnumerable validators) - : base(parameterType, parameterKind, property, description, converter, defaultValue, - null, valueProvider, validators, argument.IsRequired, false) - { - Value = argument.ValueName; - Position = argument.Position; - } +internal sealed class CommandArgument : CommandParameter +{ + public string Value { get; } + public int Position { get; set; } + + public CommandArgument( + Type parameterType, ParameterKind parameterKind, PropertyInfo property, string? description, + TypeConverterAttribute? converter, DefaultValueAttribute? defaultValue, + CommandArgumentAttribute argument, ParameterValueProviderAttribute? valueProvider, + IEnumerable validators) + : base(parameterType, parameterKind, property, description, converter, defaultValue, + null, valueProvider, validators, argument.IsRequired, false) + { + Value = argument.ValueName; + Position = argument.Position; } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Modelling/CommandContainerExtensions.cs b/src/Spectre.Console/Cli/Internal/Modelling/CommandContainerExtensions.cs index fbf7419..6941a57 100644 --- a/src/Spectre.Console/Cli/Internal/Modelling/CommandContainerExtensions.cs +++ b/src/Spectre.Console/Cli/Internal/Modelling/CommandContainerExtensions.cs @@ -1,21 +1,20 @@ using System.Linq; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal static class CommandContainerExtensions { - internal static class CommandContainerExtensions + public static CommandInfo? FindCommand(this ICommandContainer root, string name, CaseSensitivity sensitivity) { - public static CommandInfo? FindCommand(this ICommandContainer root, string name, CaseSensitivity sensitivity) + var result = root.Commands.FirstOrDefault( + c => c.Name.Equals(name, sensitivity.GetStringComparison(CommandPart.CommandName))); + + if (result == null) { - var result = root.Commands.FirstOrDefault( - c => c.Name.Equals(name, sensitivity.GetStringComparison(CommandPart.CommandName))); - - if (result == null) - { - result = root.Commands.FirstOrDefault( - c => c.Aliases.Contains(name, sensitivity.GetStringComparer(CommandPart.CommandName))); - } - - return result; + result = root.Commands.FirstOrDefault( + c => c.Aliases.Contains(name, sensitivity.GetStringComparer(CommandPart.CommandName))); } + + return result; } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Modelling/CommandInfo.cs b/src/Spectre.Console/Cli/Internal/Modelling/CommandInfo.cs index 9dcb1b6..6f8936e 100644 --- a/src/Spectre.Console/Cli/Internal/Modelling/CommandInfo.cs +++ b/src/Spectre.Console/Cli/Internal/Modelling/CommandInfo.cs @@ -4,67 +4,66 @@ using System.ComponentModel; using System.Linq; using System.Reflection; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal sealed class CommandInfo : ICommandContainer { - internal sealed class CommandInfo : ICommandContainer + public string Name { get; } + public HashSet Aliases { get; } + public string? Description { get; } + public object? Data { get; } + public Type? CommandType { get; } + public Type SettingsType { get; } + public Func? Delegate { get; } + public bool IsDefaultCommand { get; } + public bool IsHidden { get; } + public CommandInfo? Parent { get; } + public IList Children { get; } + public IList Parameters { get; } + public IList Examples { get; } + + public bool IsBranch => CommandType == null && Delegate == null; + IList ICommandContainer.Commands => Children; + + public CommandInfo(CommandInfo? parent, ConfiguredCommand prototype) { - public string Name { get; } - public HashSet Aliases { get; } - public string? Description { get; } - public object? Data { get; } - public Type? CommandType { get; } - public Type SettingsType { get; } - public Func? Delegate { get; } - public bool IsDefaultCommand { get; } - public bool IsHidden { get; } - public CommandInfo? Parent { get; } - public IList Children { get; } - public IList Parameters { get; } - public IList Examples { get; } + Parent = parent; - public bool IsBranch => CommandType == null && Delegate == null; - IList ICommandContainer.Commands => Children; + Name = prototype.Name; + Aliases = new HashSet(prototype.Aliases); + Description = prototype.Description; + Data = prototype.Data; + CommandType = prototype.CommandType; + SettingsType = prototype.SettingsType; + Delegate = prototype.Delegate; + IsDefaultCommand = prototype.IsDefaultCommand; + IsHidden = prototype.IsHidden; - public CommandInfo(CommandInfo? parent, ConfiguredCommand prototype) + Children = new List(); + Parameters = new List(); + Examples = prototype.Examples ?? new List(); + + if (CommandType != null && string.IsNullOrWhiteSpace(Description)) { - Parent = parent; - - Name = prototype.Name; - Aliases = new HashSet(prototype.Aliases); - Description = prototype.Description; - Data = prototype.Data; - CommandType = prototype.CommandType; - SettingsType = prototype.SettingsType; - Delegate = prototype.Delegate; - IsDefaultCommand = prototype.IsDefaultCommand; - IsHidden = prototype.IsHidden; - - Children = new List(); - Parameters = new List(); - Examples = prototype.Examples ?? new List(); - - if (CommandType != null && string.IsNullOrWhiteSpace(Description)) + var description = CommandType.GetCustomAttribute(); + if (description != null) { - var description = CommandType.GetCustomAttribute(); - if (description != null) - { - Description = description.Description; - } + Description = description.Description; } } - - public List Flatten() - { - var result = new Stack(); - - var current = this; - while (current != null) - { - result.Push(current); - current = current.Parent; - } - - return result.ToList(); - } } -} + + public List Flatten() + { + var result = new Stack(); + + var current = this; + while (current != null) + { + result.Push(current); + current = current.Parent; + } + + return result.ToList(); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Modelling/CommandInfoExtensions.cs b/src/Spectre.Console/Cli/Internal/Modelling/CommandInfoExtensions.cs index 00940a7..76a9d09 100644 --- a/src/Spectre.Console/Cli/Internal/Modelling/CommandInfoExtensions.cs +++ b/src/Spectre.Console/Cli/Internal/Modelling/CommandInfoExtensions.cs @@ -1,79 +1,78 @@ using System.Linq; -namespace Spectre.Console.Cli -{ - internal static class CommandInfoExtensions - { - public static bool HaveParentWithOption(this CommandInfo command, CommandOption option) - { - var parent = command?.Parent; - while (parent != null) - { - foreach (var parentOption in parent.Parameters.OfType()) - { - if (option.HaveSameBackingPropertyAs(parentOption)) - { - return true; - } - } +namespace Spectre.Console.Cli; - parent = parent.Parent; +internal static class CommandInfoExtensions +{ + public static bool HaveParentWithOption(this CommandInfo command, CommandOption option) + { + var parent = command?.Parent; + while (parent != null) + { + foreach (var parentOption in parent.Parameters.OfType()) + { + if (option.HaveSameBackingPropertyAs(parentOption)) + { + return true; + } } - return false; + parent = parent.Parent; } - public static bool AllowParentOption(this CommandInfo command, CommandOption option) - { - // Got an immediate parent? - if (command?.Parent != null) - { - // Is the current node's settings type the same as the previous one? - if (command.SettingsType == command.Parent.SettingsType) - { - var parameters = command.Parent.Parameters.OfType().ToArray(); - if (parameters.Length > 0) - { - foreach (var parentOption in parameters) - { - // Is this the same one? - if (option.HaveSameBackingPropertyAs(parentOption)) - { - // Is it part of the same settings class. - if (option.Property.DeclaringType == command.SettingsType) - { - // Allow it. - return true; - } + return false; + } - // Don't allow it. - return false; + public static bool AllowParentOption(this CommandInfo command, CommandOption option) + { + // Got an immediate parent? + if (command?.Parent != null) + { + // Is the current node's settings type the same as the previous one? + if (command.SettingsType == command.Parent.SettingsType) + { + var parameters = command.Parent.Parameters.OfType().ToArray(); + if (parameters.Length > 0) + { + foreach (var parentOption in parameters) + { + // Is this the same one? + if (option.HaveSameBackingPropertyAs(parentOption)) + { + // Is it part of the same settings class. + if (option.Property.DeclaringType == command.SettingsType) + { + // Allow it. + return true; } + + // Don't allow it. + return false; } } } } - - return false; } - public static bool HaveParentWithArgument(this CommandInfo command, CommandArgument argument) - { - var parent = command?.Parent; - while (parent != null) - { - foreach (var parentOption in parent.Parameters.OfType()) - { - if (argument.HaveSameBackingPropertyAs(parentOption)) - { - return true; - } - } + return false; + } - parent = parent.Parent; + public static bool HaveParentWithArgument(this CommandInfo command, CommandArgument argument) + { + var parent = command?.Parent; + while (parent != null) + { + foreach (var parentOption in parent.Parameters.OfType()) + { + if (argument.HaveSameBackingPropertyAs(parentOption)) + { + return true; + } } - return false; + parent = parent.Parent; } + + return false; } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Modelling/CommandModel.cs b/src/Spectre.Console/Cli/Internal/Modelling/CommandModel.cs index 902c2ca..ae54942 100644 --- a/src/Spectre.Console/Cli/Internal/Modelling/CommandModel.cs +++ b/src/Spectre.Console/Cli/Internal/Modelling/CommandModel.cs @@ -4,48 +4,47 @@ using System.Diagnostics; using System.IO; using System.Reflection; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal sealed class CommandModel : ICommandContainer { - internal sealed class CommandModel : ICommandContainer + public string? ApplicationName { get; } + public ParsingMode ParsingMode { get; } + public CommandInfo? DefaultCommand { get; } + public IList Commands { get; } + public IList Examples { get; } + + public CommandModel( + CommandAppSettings settings, + CommandInfo? defaultCommand, + IEnumerable commands, + IEnumerable examples) { - public string? ApplicationName { get; } - public ParsingMode ParsingMode { get; } - public CommandInfo? DefaultCommand { get; } - public IList Commands { get; } - public IList Examples { get; } - - public CommandModel( - CommandAppSettings settings, - CommandInfo? defaultCommand, - IEnumerable commands, - IEnumerable examples) - { - ApplicationName = settings.ApplicationName; - ParsingMode = settings.ParsingMode; - DefaultCommand = defaultCommand; - Commands = new List(commands ?? Array.Empty()); - Examples = new List(examples ?? Array.Empty()); - } - - public string GetApplicationName() - { - return - ApplicationName ?? - Path.GetFileName(GetApplicationFile()) ?? // null is propagated by GetFileName - "?"; - } - - private static string? GetApplicationFile() - { - var location = Assembly.GetEntryAssembly()?.Location; - if (string.IsNullOrWhiteSpace(location)) - { - // this is special case for single file executable - // (Assembly.Location returns empty string) - return Process.GetCurrentProcess().MainModule?.FileName; - } - - return location; - } + ApplicationName = settings.ApplicationName; + ParsingMode = settings.ParsingMode; + DefaultCommand = defaultCommand; + Commands = new List(commands ?? Array.Empty()); + Examples = new List(examples ?? Array.Empty()); } -} + + public string GetApplicationName() + { + return + ApplicationName ?? + Path.GetFileName(GetApplicationFile()) ?? // null is propagated by GetFileName + "?"; + } + + private static string? GetApplicationFile() + { + var location = Assembly.GetEntryAssembly()?.Location; + if (string.IsNullOrWhiteSpace(location)) + { + // this is special case for single file executable + // (Assembly.Location returns empty string) + return Process.GetCurrentProcess().MainModule?.FileName; + } + + return location; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Modelling/CommandModelBuilder.cs b/src/Spectre.Console/Cli/Internal/Modelling/CommandModelBuilder.cs index 03eb493..7511c14 100644 --- a/src/Spectre.Console/Cli/Internal/Modelling/CommandModelBuilder.cs +++ b/src/Spectre.Console/Cli/Internal/Modelling/CommandModelBuilder.cs @@ -4,250 +4,249 @@ using System.ComponentModel; using System.Linq; using System.Reflection; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal static class CommandModelBuilder { - internal static class CommandModelBuilder + // Consider removing this in favor for value tuples at some point. + private sealed class OrderedProperties { - // Consider removing this in favor for value tuples at some point. - private sealed class OrderedProperties - { - public int Level { get; } - public int SortOrder { get; } - public PropertyInfo[] Properties { get; } + public int Level { get; } + public int SortOrder { get; } + public PropertyInfo[] Properties { get; } - public OrderedProperties(int level, int sortOrder, PropertyInfo[] properties) - { - Level = level; - SortOrder = sortOrder; - Properties = properties; - } + public OrderedProperties(int level, int sortOrder, PropertyInfo[] properties) + { + Level = level; + SortOrder = sortOrder; + Properties = properties; + } + } + + public static CommandModel Build(IConfiguration configuration) + { + var result = new List(); + foreach (var command in configuration.Commands) + { + result.Add(Build(null, command)); } - public static CommandModel Build(IConfiguration configuration) + var defaultCommand = default(CommandInfo); + if (configuration.DefaultCommand != null) { - var result = new List(); - foreach (var command in configuration.Commands) - { - result.Add(Build(null, command)); - } + // Add the examples from the configuration to the default command. + configuration.DefaultCommand.Examples.AddRange(configuration.Examples); - var defaultCommand = default(CommandInfo); - if (configuration.DefaultCommand != null) - { - // Add the examples from the configuration to the default command. - configuration.DefaultCommand.Examples.AddRange(configuration.Examples); - - // Build the default command. - defaultCommand = Build(null, configuration.DefaultCommand); - } - - // Create the command model and validate it. - var model = new CommandModel(configuration.Settings, defaultCommand, result, configuration.Examples); - CommandModelValidator.Validate(model, configuration.Settings); - - return model; + // Build the default command. + defaultCommand = Build(null, configuration.DefaultCommand); } - private static CommandInfo Build(CommandInfo? parent, ConfiguredCommand command) + // Create the command model and validate it. + var model = new CommandModel(configuration.Settings, defaultCommand, result, configuration.Examples); + CommandModelValidator.Validate(model, configuration.Settings); + + return model; + } + + private static CommandInfo Build(CommandInfo? parent, ConfiguredCommand command) + { + var info = new CommandInfo(parent, command); + + foreach (var parameter in GetParameters(info)) { - var info = new CommandInfo(parent, command); - - foreach (var parameter in GetParameters(info)) - { - info.Parameters.Add(parameter); - } - - foreach (var childCommand in command.Children) - { - var child = Build(info, childCommand); - info.Children.Add(child); - } - - // Normalize argument positions. - var index = 0; - foreach (var argument in info.Parameters.OfType() - .OrderBy(argument => argument.Position)) - { - argument.Position = index; - index++; - } - - return info; + info.Parameters.Add(parameter); } - private static IEnumerable GetParameters(CommandInfo command) + foreach (var childCommand in command.Children) { - var result = new List(); - var argumentPosition = 0; + var child = Build(info, childCommand); + info.Children.Add(child); + } - // We need to get parameters in order of the class where they were defined. - // We assign each inheritance level a value that is used to properly sort the - // arguments when iterating over them. - IEnumerable GetPropertiesInOrder() + // Normalize argument positions. + var index = 0; + foreach (var argument in info.Parameters.OfType() + .OrderBy(argument => argument.Position)) + { + argument.Position = index; + index++; + } + + return info; + } + + private static IEnumerable GetParameters(CommandInfo command) + { + var result = new List(); + var argumentPosition = 0; + + // We need to get parameters in order of the class where they were defined. + // We assign each inheritance level a value that is used to properly sort the + // arguments when iterating over them. + IEnumerable GetPropertiesInOrder() + { + var current = command.SettingsType; + var level = 0; + var sortOrder = 0; + while (current.BaseType != null) { - var current = command.SettingsType; - var level = 0; - var sortOrder = 0; - while (current.BaseType != null) + yield return new OrderedProperties(level, sortOrder, current.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public)); + current = current.BaseType; + + // Things get a little bit complicated now. + // Only consider a setting's base type part of the + // setting, if there isn't a parent command that implements + // the setting's base type. This might come back to bite us :) + var currentCommand = command.Parent; + while (currentCommand != null) { - yield return new OrderedProperties(level, sortOrder, current.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public)); - current = current.BaseType; - - // Things get a little bit complicated now. - // Only consider a setting's base type part of the - // setting, if there isn't a parent command that implements - // the setting's base type. This might come back to bite us :) - var currentCommand = command.Parent; - while (currentCommand != null) + if (currentCommand.SettingsType == current) { - if (currentCommand.SettingsType == current) - { - level--; - break; - } - - currentCommand = currentCommand.Parent; + level--; + break; } - sortOrder--; + currentCommand = currentCommand.Parent; } + + sortOrder--; } + } - var groups = GetPropertiesInOrder(); - foreach (var group in groups.OrderBy(x => x.Level).ThenBy(x => x.SortOrder)) + var groups = GetPropertiesInOrder(); + foreach (var group in groups.OrderBy(x => x.Level).ThenBy(x => x.SortOrder)) + { + var parameters = new List(); + + foreach (var property in group.Properties) { - var parameters = new List(); - - foreach (var property in group.Properties) + if (property.IsDefined(typeof(CommandOptionAttribute))) { - if (property.IsDefined(typeof(CommandOptionAttribute))) + var attribute = property.GetCustomAttribute(); + if (attribute != null) { - var attribute = property.GetCustomAttribute(); - if (attribute != null) - { - var option = BuildOptionParameter(property, attribute); + var option = BuildOptionParameter(property, attribute); - // Any previous command has this option defined? - if (command.HaveParentWithOption(option)) + // Any previous command has this option defined? + if (command.HaveParentWithOption(option)) + { + // Do we allow it to exist on this command as well? + if (command.AllowParentOption(option)) { - // Do we allow it to exist on this command as well? - if (command.AllowParentOption(option)) - { - option.IsShadowed = true; - parameters.Add(option); - } - } - else - { - // No parent have this option. + option.IsShadowed = true; parameters.Add(option); } } - } - else if (property.IsDefined(typeof(CommandArgumentAttribute))) - { - var attribute = property.GetCustomAttribute(); - if (attribute != null) + else { - var argument = BuildArgumentParameter(property, attribute); - - // Any previous command has this argument defined? - // In that case, we should not assign the parameter to this command. - if (!command.HaveParentWithArgument(argument)) - { - parameters.Add(argument); - } + // No parent have this option. + parameters.Add(option); } } } - - // Update the position for the parameters. - foreach (var argument in parameters.OfType().OrderBy(x => x.Position)) + else if (property.IsDefined(typeof(CommandArgumentAttribute))) { - argument.Position = argumentPosition++; - } + var attribute = property.GetCustomAttribute(); + if (attribute != null) + { + var argument = BuildArgumentParameter(property, attribute); - // Add all parameters to the result. - foreach (var groupResult in parameters) - { - result.Add(groupResult); + // Any previous command has this argument defined? + // In that case, we should not assign the parameter to this command. + if (!command.HaveParentWithArgument(argument)) + { + parameters.Add(argument); + } + } } } - return result; - } - - private static CommandOption BuildOptionParameter(PropertyInfo property, CommandOptionAttribute attribute) - { - var description = property.GetCustomAttribute(); - var converter = property.GetCustomAttribute(); - var deconstructor = property.GetCustomAttribute(); - var valueProvider = property.GetCustomAttribute(); - var validators = property.GetCustomAttributes(true); - var defaultValue = property.GetCustomAttribute(); - - var kind = GetOptionKind(property.PropertyType, attribute, deconstructor, converter); - - if (defaultValue == null && property.PropertyType == typeof(bool)) + // Update the position for the parameters. + foreach (var argument in parameters.OfType().OrderBy(x => x.Position)) { - defaultValue = new DefaultValueAttribute(false); + argument.Position = argumentPosition++; } - return new CommandOption(property.PropertyType, kind, - property, description?.Description, converter, deconstructor, - attribute, valueProvider, validators, defaultValue, - attribute.ValueIsOptional); + // Add all parameters to the result. + foreach (var groupResult in parameters) + { + result.Add(groupResult); + } } - private static CommandArgument BuildArgumentParameter(PropertyInfo property, CommandArgumentAttribute attribute) - { - var description = property.GetCustomAttribute(); - var converter = property.GetCustomAttribute(); - var defaultValue = property.GetCustomAttribute(); - var valueProvider = property.GetCustomAttribute(); - var validators = property.GetCustomAttributes(true); - - var kind = GetParameterKind(property.PropertyType); - - return new CommandArgument( - property.PropertyType, kind, property, - description?.Description, converter, - defaultValue, attribute, valueProvider, - validators); - } - - private static ParameterKind GetOptionKind( - Type type, - CommandOptionAttribute attribute, - PairDeconstructorAttribute? deconstructor, - TypeConverterAttribute? converter) - { - if (attribute.ValueIsOptional) - { - return ParameterKind.FlagWithValue; - } - - if (type.IsPairDeconstructable() && (deconstructor != null || converter == null)) - { - return ParameterKind.Pair; - } - - return GetParameterKind(type); - } - - private static ParameterKind GetParameterKind(Type type) - { - if (type == typeof(bool) || type == typeof(bool?)) - { - return ParameterKind.Flag; - } - - if (type.IsArray) - { - return ParameterKind.Vector; - } - - return ParameterKind.Scalar; - } + return result; } -} + + private static CommandOption BuildOptionParameter(PropertyInfo property, CommandOptionAttribute attribute) + { + var description = property.GetCustomAttribute(); + var converter = property.GetCustomAttribute(); + var deconstructor = property.GetCustomAttribute(); + var valueProvider = property.GetCustomAttribute(); + var validators = property.GetCustomAttributes(true); + var defaultValue = property.GetCustomAttribute(); + + var kind = GetOptionKind(property.PropertyType, attribute, deconstructor, converter); + + if (defaultValue == null && property.PropertyType == typeof(bool)) + { + defaultValue = new DefaultValueAttribute(false); + } + + return new CommandOption(property.PropertyType, kind, + property, description?.Description, converter, deconstructor, + attribute, valueProvider, validators, defaultValue, + attribute.ValueIsOptional); + } + + private static CommandArgument BuildArgumentParameter(PropertyInfo property, CommandArgumentAttribute attribute) + { + var description = property.GetCustomAttribute(); + var converter = property.GetCustomAttribute(); + var defaultValue = property.GetCustomAttribute(); + var valueProvider = property.GetCustomAttribute(); + var validators = property.GetCustomAttributes(true); + + var kind = GetParameterKind(property.PropertyType); + + return new CommandArgument( + property.PropertyType, kind, property, + description?.Description, converter, + defaultValue, attribute, valueProvider, + validators); + } + + private static ParameterKind GetOptionKind( + Type type, + CommandOptionAttribute attribute, + PairDeconstructorAttribute? deconstructor, + TypeConverterAttribute? converter) + { + if (attribute.ValueIsOptional) + { + return ParameterKind.FlagWithValue; + } + + if (type.IsPairDeconstructable() && (deconstructor != null || converter == null)) + { + return ParameterKind.Pair; + } + + return GetParameterKind(type); + } + + private static ParameterKind GetParameterKind(Type type) + { + if (type == typeof(bool) || type == typeof(bool?)) + { + return ParameterKind.Flag; + } + + if (type.IsArray) + { + return ParameterKind.Vector; + } + + return ParameterKind.Scalar; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Modelling/CommandModelValidator.cs b/src/Spectre.Console/Cli/Internal/Modelling/CommandModelValidator.cs index 06a8fa0..21ce93f 100644 --- a/src/Spectre.Console/Cli/Internal/Modelling/CommandModelValidator.cs +++ b/src/Spectre.Console/Cli/Internal/Modelling/CommandModelValidator.cs @@ -2,193 +2,192 @@ using System; using System.Collections.Generic; using System.Linq; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal static class CommandModelValidator { - internal static class CommandModelValidator + public static void Validate(CommandModel model, CommandAppSettings settings) { - public static void Validate(CommandModel model, CommandAppSettings settings) + if (model is null) { - if (model is null) - { - throw new ArgumentNullException(nameof(model)); - } - - if (settings is null) - { - throw new ArgumentNullException(nameof(settings)); - } - - if (model.Commands.Count == 0 && model.DefaultCommand == null) - { - throw CommandConfigurationException.NoCommandConfigured(); - } - - foreach (var command in model.Commands) - { - // Alias collision? - foreach (var alias in command.Aliases) - { - if (model.Commands.Any(x => x.Name.Equals(alias, StringComparison.OrdinalIgnoreCase))) - { - throw CommandConfigurationException.CommandNameConflict(command, alias); - } - } - } - - Validate(model.DefaultCommand); - foreach (var command in model.Commands) - { - Validate(command); - } - - if (settings.ValidateExamples) - { - ValidateExamples(model, settings); - } + throw new ArgumentNullException(nameof(model)); } - private static void Validate(CommandInfo? command) + if (settings is null) { - if (command == null) - { - return; - } - - // Get duplicate options for command. - var duplicateOptions = GetDuplicates(command); - if (duplicateOptions.Length > 0) - { - throw CommandConfigurationException.DuplicateOption(command, duplicateOptions); - } - - // No children? - if (command.IsBranch && command.Children.Count == 0) - { - throw CommandConfigurationException.BranchHasNoChildren(command); - } - - var arguments = command.Parameters - .OfType() - .OrderBy(x => x.Position) - .ToList(); - - // vector arguments? - if (arguments.Any(x => x.ParameterKind == ParameterKind.Vector)) - { - // Multiple vector arguments for command? - if (arguments.Count(x => x.ParameterKind == ParameterKind.Vector) > 1) - { - throw CommandConfigurationException.TooManyVectorArguments(command); - } - - // Make sure that the vector argument is specified last. - if (arguments.Last().ParameterKind != ParameterKind.Vector) - { - throw CommandConfigurationException.VectorArgumentNotSpecifiedLast(command); - } - } - - // Arguments - foreach (var argument in arguments) - { - if (argument.Required && argument.DefaultValue != null) - { - throw CommandConfigurationException.RequiredArgumentsCannotHaveDefaultValue(argument); - } - } - - // Options - var options = command.Parameters.OfType(); - foreach (var option in options) - { - // Pair deconstructable? - if (option.Property.PropertyType.IsPairDeconstructable()) - { - if (option.PairDeconstructor != null && option.Converter != null) - { - throw CommandConfigurationException.OptionBothHasPairDeconstructorAndTypeParameter(option); - } - } - else if (option.PairDeconstructor != null) - { - throw CommandConfigurationException.OptionTypeDoesNotSupportDeconstruction(option); - } - - // Optional options that are not flags? - if (option.ParameterKind == ParameterKind.FlagWithValue && !option.IsFlagValue()) - { - throw CommandConfigurationException.OptionalOptionValueMustBeFlagWithValue(option); - } - } - - // Validate child commands. - foreach (var childCommand in command.Children) - { - Validate(childCommand); - } + throw new ArgumentNullException(nameof(settings)); } - private static void ValidateExamples(CommandModel model, CommandAppSettings settings) + if (model.Commands.Count == 0 && model.DefaultCommand == null) { - var examples = new List(); - examples.AddRangeIfNotNull(model.Examples); + throw CommandConfigurationException.NoCommandConfigured(); + } - // Get all examples. - var queue = new Queue(new[] { model }); - while (queue.Count > 0) + foreach (var command in model.Commands) + { + // Alias collision? + foreach (var alias in command.Aliases) { - var current = queue.Dequeue(); - - foreach (var command in current.Commands) + if (model.Commands.Any(x => x.Name.Equals(alias, StringComparison.OrdinalIgnoreCase))) { - examples.AddRangeIfNotNull(command.Examples); - queue.Enqueue(command); - } - } - - // Validate all examples. - foreach (var example in examples) - { - try - { - var parser = new CommandTreeParser(model, settings, ParsingMode.Strict); - parser.Parse(example); - } - catch (Exception ex) - { - throw new CommandConfigurationException("Validation of examples failed.", ex); + throw CommandConfigurationException.CommandNameConflict(command, alias); } } } - private static string[] GetDuplicates(CommandInfo command) + Validate(model.DefaultCommand); + foreach (var command in model.Commands) { - var result = new Dictionary(StringComparer.Ordinal); + Validate(command); + } - void AddToResult(IEnumerable keys) - { - foreach (var key in keys) - { - if (!string.IsNullOrWhiteSpace(key)) - { - if (!result.ContainsKey(key)) - { - result.Add(key, 0); - } - - result[key]++; - } - } - } - - foreach (var option in command.Parameters.OfType()) - { - AddToResult(option.ShortNames); - AddToResult(option.LongNames); - } - - return result.Where(x => x.Value > 1) - .Select(x => x.Key).ToArray(); + if (settings.ValidateExamples) + { + ValidateExamples(model, settings); } } -} + + private static void Validate(CommandInfo? command) + { + if (command == null) + { + return; + } + + // Get duplicate options for command. + var duplicateOptions = GetDuplicates(command); + if (duplicateOptions.Length > 0) + { + throw CommandConfigurationException.DuplicateOption(command, duplicateOptions); + } + + // No children? + if (command.IsBranch && command.Children.Count == 0) + { + throw CommandConfigurationException.BranchHasNoChildren(command); + } + + var arguments = command.Parameters + .OfType() + .OrderBy(x => x.Position) + .ToList(); + + // vector arguments? + if (arguments.Any(x => x.ParameterKind == ParameterKind.Vector)) + { + // Multiple vector arguments for command? + if (arguments.Count(x => x.ParameterKind == ParameterKind.Vector) > 1) + { + throw CommandConfigurationException.TooManyVectorArguments(command); + } + + // Make sure that the vector argument is specified last. + if (arguments.Last().ParameterKind != ParameterKind.Vector) + { + throw CommandConfigurationException.VectorArgumentNotSpecifiedLast(command); + } + } + + // Arguments + foreach (var argument in arguments) + { + if (argument.Required && argument.DefaultValue != null) + { + throw CommandConfigurationException.RequiredArgumentsCannotHaveDefaultValue(argument); + } + } + + // Options + var options = command.Parameters.OfType(); + foreach (var option in options) + { + // Pair deconstructable? + if (option.Property.PropertyType.IsPairDeconstructable()) + { + if (option.PairDeconstructor != null && option.Converter != null) + { + throw CommandConfigurationException.OptionBothHasPairDeconstructorAndTypeParameter(option); + } + } + else if (option.PairDeconstructor != null) + { + throw CommandConfigurationException.OptionTypeDoesNotSupportDeconstruction(option); + } + + // Optional options that are not flags? + if (option.ParameterKind == ParameterKind.FlagWithValue && !option.IsFlagValue()) + { + throw CommandConfigurationException.OptionalOptionValueMustBeFlagWithValue(option); + } + } + + // Validate child commands. + foreach (var childCommand in command.Children) + { + Validate(childCommand); + } + } + + private static void ValidateExamples(CommandModel model, CommandAppSettings settings) + { + var examples = new List(); + examples.AddRangeIfNotNull(model.Examples); + + // Get all examples. + var queue = new Queue(new[] { model }); + while (queue.Count > 0) + { + var current = queue.Dequeue(); + + foreach (var command in current.Commands) + { + examples.AddRangeIfNotNull(command.Examples); + queue.Enqueue(command); + } + } + + // Validate all examples. + foreach (var example in examples) + { + try + { + var parser = new CommandTreeParser(model, settings, ParsingMode.Strict); + parser.Parse(example); + } + catch (Exception ex) + { + throw new CommandConfigurationException("Validation of examples failed.", ex); + } + } + } + + private static string[] GetDuplicates(CommandInfo command) + { + var result = new Dictionary(StringComparer.Ordinal); + + void AddToResult(IEnumerable keys) + { + foreach (var key in keys) + { + if (!string.IsNullOrWhiteSpace(key)) + { + if (!result.ContainsKey(key)) + { + result.Add(key, 0); + } + + result[key]++; + } + } + } + + foreach (var option in command.Parameters.OfType()) + { + AddToResult(option.ShortNames); + AddToResult(option.LongNames); + } + + return result.Where(x => x.Value > 1) + .Select(x => x.Key).ToArray(); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Modelling/CommandOption.cs b/src/Spectre.Console/Cli/Internal/Modelling/CommandOption.cs index df0ef73..ce150b8 100644 --- a/src/Spectre.Console/Cli/Internal/Modelling/CommandOption.cs +++ b/src/Spectre.Console/Cli/Internal/Modelling/CommandOption.cs @@ -3,34 +3,33 @@ using System.Collections.Generic; using System.ComponentModel; using System.Reflection; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal sealed class CommandOption : CommandParameter { - internal sealed class CommandOption : CommandParameter + public IReadOnlyList LongNames { get; } + public IReadOnlyList ShortNames { get; } + public string? ValueName { get; } + public bool ValueIsOptional { get; } + public bool IsShadowed { get; set; } + + public CommandOption( + Type parameterType, ParameterKind parameterKind, PropertyInfo property, string? description, + TypeConverterAttribute? converter, PairDeconstructorAttribute? deconstructor, + CommandOptionAttribute optionAttribute, ParameterValueProviderAttribute? valueProvider, + IEnumerable validators, + DefaultValueAttribute? defaultValue, bool valueIsOptional) + : base(parameterType, parameterKind, property, description, converter, + defaultValue, deconstructor, valueProvider, validators, false, optionAttribute.IsHidden) { - public IReadOnlyList LongNames { get; } - public IReadOnlyList ShortNames { get; } - public string? ValueName { get; } - public bool ValueIsOptional { get; } - public bool IsShadowed { get; set; } + LongNames = optionAttribute.LongNames; + ShortNames = optionAttribute.ShortNames; + ValueName = optionAttribute.ValueName; + ValueIsOptional = valueIsOptional; + } - public CommandOption( - Type parameterType, ParameterKind parameterKind, PropertyInfo property, string? description, - TypeConverterAttribute? converter, PairDeconstructorAttribute? deconstructor, - CommandOptionAttribute optionAttribute, ParameterValueProviderAttribute? valueProvider, - IEnumerable validators, - DefaultValueAttribute? defaultValue, bool valueIsOptional) - : base(parameterType, parameterKind, property, description, converter, - defaultValue, deconstructor, valueProvider, validators, false, optionAttribute.IsHidden) - { - LongNames = optionAttribute.LongNames; - ShortNames = optionAttribute.ShortNames; - ValueName = optionAttribute.ValueName; - ValueIsOptional = valueIsOptional; - } - - public string GetOptionName() - { - return LongNames.Count > 0 ? LongNames[0] : ShortNames[0]; - } + public string GetOptionName() + { + return LongNames.Count > 0 ? LongNames[0] : ShortNames[0]; } } \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Modelling/CommandParameter.cs b/src/Spectre.Console/Cli/Internal/Modelling/CommandParameter.cs index 318b692..84c481c 100644 --- a/src/Spectre.Console/Cli/Internal/Modelling/CommandParameter.cs +++ b/src/Spectre.Console/Cli/Internal/Modelling/CommandParameter.cs @@ -4,153 +4,152 @@ using System.ComponentModel; using System.Linq; using System.Reflection; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal abstract class CommandParameter : ICommandParameterInfo { - internal abstract class CommandParameter : ICommandParameterInfo + public Guid Id { get; } + public Type ParameterType { get; } + public ParameterKind ParameterKind { get; } + public PropertyInfo Property { get; } + public string? Description { get; } + public DefaultValueAttribute? DefaultValue { get; } + public TypeConverterAttribute? Converter { get; } + public PairDeconstructorAttribute? PairDeconstructor { get; } + public List Validators { get; } + public ParameterValueProviderAttribute? ValueProvider { get; } + public bool Required { get; set; } + public bool IsHidden { get; } + public string PropertyName => Property.Name; + + public virtual bool WantRawValue => ParameterType.IsPairDeconstructable() + && (PairDeconstructor != null || Converter == null); + + protected CommandParameter( + Type parameterType, ParameterKind parameterKind, PropertyInfo property, + string? description, TypeConverterAttribute? converter, + DefaultValueAttribute? defaultValue, + PairDeconstructorAttribute? deconstructor, + ParameterValueProviderAttribute? valueProvider, + IEnumerable validators, bool required, bool isHidden) { - public Guid Id { get; } - public Type ParameterType { get; } - public ParameterKind ParameterKind { get; } - public PropertyInfo Property { get; } - public string? Description { get; } - public DefaultValueAttribute? DefaultValue { get; } - public TypeConverterAttribute? Converter { get; } - public PairDeconstructorAttribute? PairDeconstructor { get; } - public List Validators { get; } - public ParameterValueProviderAttribute? ValueProvider { get; } - public bool Required { get; set; } - public bool IsHidden { get; } - public string PropertyName => Property.Name; + Id = Guid.NewGuid(); + ParameterType = parameterType; + ParameterKind = parameterKind; + Property = property; + Description = description; + Converter = converter; + DefaultValue = defaultValue; + PairDeconstructor = deconstructor; + ValueProvider = valueProvider; + Validators = new List(validators ?? Array.Empty()); + Required = required; + IsHidden = isHidden; + } - public virtual bool WantRawValue => ParameterType.IsPairDeconstructable() - && (PairDeconstructor != null || Converter == null); + public bool IsFlagValue() + { + return ParameterType.GetInterfaces().Any(i => i == typeof(IFlagValue)); + } - protected CommandParameter( - Type parameterType, ParameterKind parameterKind, PropertyInfo property, - string? description, TypeConverterAttribute? converter, - DefaultValueAttribute? defaultValue, - PairDeconstructorAttribute? deconstructor, - ParameterValueProviderAttribute? valueProvider, - IEnumerable validators, bool required, bool isHidden) + public bool HaveSameBackingPropertyAs(CommandParameter other) + { + return CommandParameterComparer.ByBackingProperty.Equals(this, other); + } + + public void Assign(CommandSettings settings, ITypeResolver resolver, object? value) + { + // Is the property pair deconstructable? + // TODO: This needs to be better defined + if (Property.PropertyType.IsPairDeconstructable() && WantRawValue) { - Id = Guid.NewGuid(); - ParameterType = parameterType; - ParameterKind = parameterKind; - Property = property; - Description = description; - Converter = converter; - DefaultValue = defaultValue; - PairDeconstructor = deconstructor; - ValueProvider = valueProvider; - Validators = new List(validators ?? Array.Empty()); - Required = required; - IsHidden = isHidden; - } + var genericTypes = Property.PropertyType.GetGenericArguments(); - public bool IsFlagValue() - { - return ParameterType.GetInterfaces().Any(i => i == typeof(IFlagValue)); - } - - public bool HaveSameBackingPropertyAs(CommandParameter other) - { - return CommandParameterComparer.ByBackingProperty.Equals(this, other); - } - - public void Assign(CommandSettings settings, ITypeResolver resolver, object? value) - { - // Is the property pair deconstructable? - // TODO: This needs to be better defined - if (Property.PropertyType.IsPairDeconstructable() && WantRawValue) + var multimap = (IMultiMap?)Property.GetValue(settings); + if (multimap == null) { - var genericTypes = Property.PropertyType.GetGenericArguments(); - - var multimap = (IMultiMap?)Property.GetValue(settings); + multimap = Activator.CreateInstance(typeof(MultiMap<,>).MakeGenericType(genericTypes[0], genericTypes[1])) as IMultiMap; if (multimap == null) { - multimap = Activator.CreateInstance(typeof(MultiMap<,>).MakeGenericType(genericTypes[0], genericTypes[1])) as IMultiMap; - if (multimap == null) - { - throw new InvalidOperationException("Could not create multimap"); - } + throw new InvalidOperationException("Could not create multimap"); } - - // Create deconstructor. - var deconstructorType = PairDeconstructor?.Type ?? typeof(DefaultPairDeconstructor); - if (!(resolver.Resolve(deconstructorType) is IPairDeconstructor deconstructor)) - { - if (!(Activator.CreateInstance(deconstructorType) is IPairDeconstructor activatedDeconstructor)) - { - throw new InvalidOperationException($"Could not create pair deconstructor."); - } - - deconstructor = activatedDeconstructor; - } - - // Deconstruct and add to multimap. - var pair = deconstructor.Deconstruct(resolver, genericTypes[0], genericTypes[1], value as string); - if (pair.Key != null) - { - multimap.Add(pair); - } - - value = multimap; } - else if (Property.PropertyType.IsArray) + + // Create deconstructor. + var deconstructorType = PairDeconstructor?.Type ?? typeof(DefaultPairDeconstructor); + if (!(resolver.Resolve(deconstructorType) is IPairDeconstructor deconstructor)) { - // Add a new item to the array - var array = (Array?)Property.GetValue(settings); - Array newArray; - - var elementType = Property.PropertyType.GetElementType(); - if (elementType == null) + if (!(Activator.CreateInstance(deconstructorType) is IPairDeconstructor activatedDeconstructor)) { - throw new InvalidOperationException("Could not get property type."); + throw new InvalidOperationException($"Could not create pair deconstructor."); } - if (array == null) - { - newArray = Array.CreateInstance(elementType, 1); - } - else - { - newArray = Array.CreateInstance(elementType, array.Length + 1); - array.CopyTo(newArray, 0); - } - - newArray.SetValue(value, newArray.Length - 1); - value = newArray; + deconstructor = activatedDeconstructor; } - else if (IsFlagValue()) + + // Deconstruct and add to multimap. + var pair = deconstructor.Deconstruct(resolver, genericTypes[0], genericTypes[1], value as string); + if (pair.Key != null) { - var flagValue = (IFlagValue?)Property.GetValue(settings); + multimap.Add(pair); + } + + value = multimap; + } + else if (Property.PropertyType.IsArray) + { + // Add a new item to the array + var array = (Array?)Property.GetValue(settings); + Array newArray; + + var elementType = Property.PropertyType.GetElementType(); + if (elementType == null) + { + throw new InvalidOperationException("Could not get property type."); + } + + if (array == null) + { + newArray = Array.CreateInstance(elementType, 1); + } + else + { + newArray = Array.CreateInstance(elementType, array.Length + 1); + array.CopyTo(newArray, 0); + } + + newArray.SetValue(value, newArray.Length - 1); + value = newArray; + } + else if (IsFlagValue()) + { + var flagValue = (IFlagValue?)Property.GetValue(settings); + if (flagValue == null) + { + flagValue = (IFlagValue?)Activator.CreateInstance(ParameterType); if (flagValue == null) { - flagValue = (IFlagValue?)Activator.CreateInstance(ParameterType); - if (flagValue == null) - { - throw new InvalidOperationException("Could not create flag value."); - } + throw new InvalidOperationException("Could not create flag value."); } - - if (value != null) - { - // Null means set, but not with a valid value. - flagValue.Value = value; - } - - // If the parameter was mapped, then it's set. - flagValue.IsSet = true; - - value = flagValue; } - Property.SetValue(settings, value); + if (value != null) + { + // Null means set, but not with a valid value. + flagValue.Value = value; + } + + // If the parameter was mapped, then it's set. + flagValue.IsSet = true; + + value = flagValue; } - public object? Get(CommandSettings settings) - { - return Property.GetValue(settings); - } + Property.SetValue(settings, value); + } + + public object? Get(CommandSettings settings) + { + return Property.GetValue(settings); } } \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Modelling/CommandParameterComparer.cs b/src/Spectre.Console/Cli/Internal/Modelling/CommandParameterComparer.cs index b5ccf16..fa40155 100644 --- a/src/Spectre.Console/Cli/Internal/Modelling/CommandParameterComparer.cs +++ b/src/Spectre.Console/Cli/Internal/Modelling/CommandParameterComparer.cs @@ -1,32 +1,31 @@ using System.Collections.Generic; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal static class CommandParameterComparer { - internal static class CommandParameterComparer + public static readonly ByBackingPropertyComparer ByBackingProperty = new ByBackingPropertyComparer(); + + public sealed class ByBackingPropertyComparer : IEqualityComparer { - public static readonly ByBackingPropertyComparer ByBackingProperty = new ByBackingPropertyComparer(); - - public sealed class ByBackingPropertyComparer : IEqualityComparer + public bool Equals(CommandParameter? x, CommandParameter? y) { - public bool Equals(CommandParameter? x, CommandParameter? y) + if (x is null || y is null) { - if (x is null || y is null) - { - return false; - } - - if (ReferenceEquals(x, y)) - { - return true; - } - - return x.Property.MetadataToken == y.Property.MetadataToken; + return false; } - public int GetHashCode(CommandParameter? obj) + if (ReferenceEquals(x, y)) { - return obj?.Property?.MetadataToken.GetHashCode() ?? 0; + return true; } + + return x.Property.MetadataToken == y.Property.MetadataToken; + } + + public int GetHashCode(CommandParameter? obj) + { + return obj?.Property?.MetadataToken.GetHashCode() ?? 0; } } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Modelling/ICommandContainer.cs b/src/Spectre.Console/Cli/Internal/Modelling/ICommandContainer.cs index 7e28721..98ff861 100644 --- a/src/Spectre.Console/Cli/Internal/Modelling/ICommandContainer.cs +++ b/src/Spectre.Console/Cli/Internal/Modelling/ICommandContainer.cs @@ -1,15 +1,14 @@ using System.Collections.Generic; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// Represents a command container. +/// +internal interface ICommandContainer { /// - /// Represents a command container. + /// Gets all commands in the container. /// - internal interface ICommandContainer - { - /// - /// Gets all commands in the container. - /// - IList Commands { get; } - } -} + IList Commands { get; } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Modelling/ParameterKind.cs b/src/Spectre.Console/Cli/Internal/Modelling/ParameterKind.cs index bf0541c..ee139b4 100644 --- a/src/Spectre.Console/Cli/Internal/Modelling/ParameterKind.cs +++ b/src/Spectre.Console/Cli/Internal/Modelling/ParameterKind.cs @@ -1,22 +1,21 @@ using System.ComponentModel; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal enum ParameterKind { - internal enum ParameterKind - { - [Description("flag")] - Flag = 0, + [Description("flag")] + Flag = 0, - [Description("scalar")] - Scalar = 1, + [Description("scalar")] + Scalar = 1, - [Description("vector")] - Vector = 2, + [Description("vector")] + Vector = 2, - [Description("flagvalue")] - FlagWithValue = 3, + [Description("flagvalue")] + FlagWithValue = 3, - [Description("pair")] - Pair = 4, - } + [Description("pair")] + Pair = 4, } \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Parsing/CommandTree.cs b/src/Spectre.Console/Cli/Internal/Parsing/CommandTree.cs index a11ef65..0a8946a 100644 --- a/src/Spectre.Console/Cli/Internal/Parsing/CommandTree.cs +++ b/src/Spectre.Console/Cli/Internal/Parsing/CommandTree.cs @@ -1,37 +1,36 @@ using System.Collections.Generic; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal sealed class CommandTree { - internal sealed class CommandTree + public CommandInfo Command { get; } + public List Mapped { get; } + public List Unmapped { get; } + public CommandTree? Parent { get; } + public CommandTree? Next { get; set; } + public bool ShowHelp { get; set; } + + public CommandTree(CommandTree? parent, CommandInfo command) { - public CommandInfo Command { get; } - public List Mapped { get; } - public List Unmapped { get; } - public CommandTree? Parent { get; } - public CommandTree? Next { get; set; } - public bool ShowHelp { get; set; } + Parent = parent; + Command = command; + Mapped = new List(); + Unmapped = new List(); + } - public CommandTree(CommandTree? parent, CommandInfo command) + public ICommand CreateCommand(ITypeResolver resolver) + { + if (Command.Delegate != null) { - Parent = parent; - Command = command; - Mapped = new List(); - Unmapped = new List(); + return new DelegateCommand(Command.Delegate); } - public ICommand CreateCommand(ITypeResolver resolver) + if (resolver.Resolve(Command.CommandType) is ICommand command) { - if (Command.Delegate != null) - { - return new DelegateCommand(Command.Delegate); - } - - if (resolver.Resolve(Command.CommandType) is ICommand command) - { - return command; - } - - throw CommandParseException.CouldNotCreateCommand(Command.CommandType); + return command; } + + throw CommandParseException.CouldNotCreateCommand(Command.CommandType); } } \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Parsing/CommandTreeExtensions.cs b/src/Spectre.Console/Cli/Internal/Parsing/CommandTreeExtensions.cs index 8819423..4f451db 100644 --- a/src/Spectre.Console/Cli/Internal/Parsing/CommandTreeExtensions.cs +++ b/src/Spectre.Console/Cli/Internal/Parsing/CommandTreeExtensions.cs @@ -1,70 +1,69 @@ using System; using System.Linq; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal static class CommandTreeExtensions { - internal static class CommandTreeExtensions + public static CommandTree? GetRootCommand(this CommandTree node) { - public static CommandTree? GetRootCommand(this CommandTree node) + while (node.Parent != null) { - while (node.Parent != null) - { - node = node.Parent; - } - - return node; + node = node.Parent; } - public static CommandTree GetLeafCommand(this CommandTree node) - { - while (node.Next != null) - { - node = node.Next; - } - - return node; - } - - public static bool HasArguments(this CommandTree tree) - { - return tree.Command.Parameters.OfType().Any(); - } - - public static CommandArgument? FindArgument(this CommandTree tree, int position) - { - return tree.Command.Parameters - .OfType() - .FirstOrDefault(c => c.Position == position); - } - - public static CommandOption? FindOption(this CommandTree tree, string name, bool longOption, CaseSensitivity sensitivity) - { - return tree.Command.Parameters - .OfType() - .FirstOrDefault(o => longOption - ? o.LongNames.Contains(name, sensitivity.GetStringComparer(CommandPart.LongOption)) - : o.ShortNames.Contains(name, StringComparer.Ordinal)); - } - - public static bool IsOptionMappedWithParent(this CommandTree tree, string name, bool longOption) - { - var node = tree.Parent; - while (node != null) - { - var option = node.Command?.Parameters.OfType() - .FirstOrDefault(o => longOption - ? o.LongNames.Contains(name, StringComparer.Ordinal) - : o.ShortNames.Contains(name, StringComparer.Ordinal)); - - if (option != null) - { - return node.Mapped.Any(p => p.Parameter == option); - } - - node = node.Parent; - } - - return false; - } + return node; } -} + + public static CommandTree GetLeafCommand(this CommandTree node) + { + while (node.Next != null) + { + node = node.Next; + } + + return node; + } + + public static bool HasArguments(this CommandTree tree) + { + return tree.Command.Parameters.OfType().Any(); + } + + public static CommandArgument? FindArgument(this CommandTree tree, int position) + { + return tree.Command.Parameters + .OfType() + .FirstOrDefault(c => c.Position == position); + } + + public static CommandOption? FindOption(this CommandTree tree, string name, bool longOption, CaseSensitivity sensitivity) + { + return tree.Command.Parameters + .OfType() + .FirstOrDefault(o => longOption + ? o.LongNames.Contains(name, sensitivity.GetStringComparer(CommandPart.LongOption)) + : o.ShortNames.Contains(name, StringComparer.Ordinal)); + } + + public static bool IsOptionMappedWithParent(this CommandTree tree, string name, bool longOption) + { + var node = tree.Parent; + while (node != null) + { + var option = node.Command?.Parameters.OfType() + .FirstOrDefault(o => longOption + ? o.LongNames.Contains(name, StringComparer.Ordinal) + : o.ShortNames.Contains(name, StringComparer.Ordinal)); + + if (option != null) + { + return node.Mapped.Any(p => p.Parameter == option); + } + + node = node.Parent; + } + + return false; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Parsing/CommandTreeParser.cs b/src/Spectre.Console/Cli/Internal/Parsing/CommandTreeParser.cs index a5d4930..2b794a0 100644 --- a/src/Spectre.Console/Cli/Internal/Parsing/CommandTreeParser.cs +++ b/src/Spectre.Console/Cli/Internal/Parsing/CommandTreeParser.cs @@ -2,387 +2,386 @@ using System; using System.Collections.Generic; using System.Linq; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal class CommandTreeParser { - internal class CommandTreeParser + private readonly CommandModel _configuration; + private readonly ParsingMode _parsingMode; + private readonly CommandOptionAttribute _help; + + public CaseSensitivity CaseSensitivity { get; } + + public enum State { - private readonly CommandModel _configuration; - private readonly ParsingMode _parsingMode; - private readonly CommandOptionAttribute _help; + Normal = 0, + Remaining = 1, + } - public CaseSensitivity CaseSensitivity { get; } - - public enum State + public CommandTreeParser(CommandModel configuration, ICommandAppSettings settings, ParsingMode? parsingMode = null) + { + if (settings is null) { - Normal = 0, - Remaining = 1, + throw new ArgumentNullException(nameof(settings)); } - public CommandTreeParser(CommandModel configuration, ICommandAppSettings settings, ParsingMode? parsingMode = null) + _configuration = configuration; + _parsingMode = parsingMode ?? _configuration.ParsingMode; + _help = new CommandOptionAttribute("-h|--help"); + + CaseSensitivity = settings.CaseSensitivity; + } + + public CommandTreeParserResult Parse(IEnumerable args) + { + var context = new CommandTreeParserContext(args, _parsingMode); + + var tokenizerResult = CommandTreeTokenizer.Tokenize(context.Arguments); + var tokens = tokenizerResult.Tokens; + var rawRemaining = tokenizerResult.Remaining; + + var result = default(CommandTree); + if (tokens.Count > 0) { - if (settings is null) + // Not a command? + var token = tokens.Current; + if (token == null) { - throw new ArgumentNullException(nameof(settings)); + // Should not happen, but the compiler isn't + // smart enough to realize this... + throw new CommandRuntimeException("Could not get current token."); } - _configuration = configuration; - _parsingMode = parsingMode ?? _configuration.ParsingMode; - _help = new CommandOptionAttribute("-h|--help"); - - CaseSensitivity = settings.CaseSensitivity; - } - - public CommandTreeParserResult Parse(IEnumerable args) - { - var context = new CommandTreeParserContext(args, _parsingMode); - - var tokenizerResult = CommandTreeTokenizer.Tokenize(context.Arguments); - var tokens = tokenizerResult.Tokens; - var rawRemaining = tokenizerResult.Remaining; - - var result = default(CommandTree); - if (tokens.Count > 0) + if (token.TokenKind != CommandTreeToken.Kind.String) { - // Not a command? - var token = tokens.Current; - if (token == null) - { - // Should not happen, but the compiler isn't - // smart enough to realize this... - throw new CommandRuntimeException("Could not get current token."); - } - - if (token.TokenKind != CommandTreeToken.Kind.String) - { - // Got a default command? - if (_configuration.DefaultCommand != null) - { - result = ParseCommandParameters(context, _configuration.DefaultCommand, null, tokens); - return new CommandTreeParserResult( - result, new RemainingArguments(context.GetRemainingArguments(), rawRemaining)); - } - - // Show help? - if (_help?.IsMatch(token.Value) == true) - { - return new CommandTreeParserResult( - null, new RemainingArguments(context.GetRemainingArguments(), rawRemaining)); - } - - // Unexpected option. - throw CommandParseException.UnexpectedOption(context.Arguments, token); - } - - // Does the token value match a command? - var command = _configuration.FindCommand(token.Value, CaseSensitivity); - if (command == null) - { - if (_configuration.DefaultCommand != null) - { - result = ParseCommandParameters(context, _configuration.DefaultCommand, null, tokens); - return new CommandTreeParserResult( - result, new RemainingArguments(context.GetRemainingArguments(), rawRemaining)); - } - } - - // Parse the command. - result = ParseCommand(context, _configuration, null, tokens); - } - else - { - // Is there a default command? + // Got a default command? if (_configuration.DefaultCommand != null) { result = ParseCommandParameters(context, _configuration.DefaultCommand, null, tokens); + return new CommandTreeParserResult( + result, new RemainingArguments(context.GetRemainingArguments(), rawRemaining)); } + + // Show help? + if (_help?.IsMatch(token.Value) == true) + { + return new CommandTreeParserResult( + null, new RemainingArguments(context.GetRemainingArguments(), rawRemaining)); + } + + // Unexpected option. + throw CommandParseException.UnexpectedOption(context.Arguments, token); } - return new CommandTreeParserResult( - result, new RemainingArguments(context.GetRemainingArguments(), rawRemaining)); - } - - private CommandTree ParseCommand( - CommandTreeParserContext context, - ICommandContainer current, - CommandTree? parent, - CommandTreeTokenStream stream) - { - // Find the command. - var commandToken = stream.Consume(CommandTreeToken.Kind.String); - if (commandToken == null) - { - throw new CommandRuntimeException("Could not consume token when parsing command."); - } - - var command = current.FindCommand(commandToken.Value, CaseSensitivity); + // Does the token value match a command? + var command = _configuration.FindCommand(token.Value, CaseSensitivity); if (command == null) { - throw CommandParseException.UnknownCommand(_configuration, parent, context.Arguments, commandToken); + if (_configuration.DefaultCommand != null) + { + result = ParseCommandParameters(context, _configuration.DefaultCommand, null, tokens); + return new CommandTreeParserResult( + result, new RemainingArguments(context.GetRemainingArguments(), rawRemaining)); + } } - return ParseCommandParameters(context, command, parent, stream); + // Parse the command. + result = ParseCommand(context, _configuration, null, tokens); + } + else + { + // Is there a default command? + if (_configuration.DefaultCommand != null) + { + result = ParseCommandParameters(context, _configuration.DefaultCommand, null, tokens); + } } - private CommandTree ParseCommandParameters( - CommandTreeParserContext context, - CommandInfo command, - CommandTree? parent, - CommandTreeTokenStream stream) + return new CommandTreeParserResult( + result, new RemainingArguments(context.GetRemainingArguments(), rawRemaining)); + } + + private CommandTree ParseCommand( + CommandTreeParserContext context, + ICommandContainer current, + CommandTree? parent, + CommandTreeTokenStream stream) + { + // Find the command. + var commandToken = stream.Consume(CommandTreeToken.Kind.String); + if (commandToken == null) { - context.ResetArgumentPosition(); - - var node = new CommandTree(parent, command); - while (stream.Peek() != null) - { - var token = stream.Peek(); - if (token == null) - { - // Should not happen, but the compiler isn't - // smart enough to realize this... - throw new CommandRuntimeException("Could not get the next token."); - } - - switch (token.TokenKind) - { - case CommandTreeToken.Kind.LongOption: - // Long option - ParseOption(context, stream, token, node, true); - break; - case CommandTreeToken.Kind.ShortOption: - // Short option - ParseOption(context, stream, token, node, false); - break; - case CommandTreeToken.Kind.String: - // Command - ParseString(context, stream, node); - break; - case CommandTreeToken.Kind.Remaining: - // Remaining - stream.Consume(CommandTreeToken.Kind.Remaining); - context.State = State.Remaining; - break; - default: - throw new InvalidOperationException($"Encountered unknown token ({token.TokenKind})."); - } - } - - // Add unmapped parameters. - foreach (var parameter in node.Command.Parameters) - { - if (node.Mapped.All(m => m.Parameter != parameter)) - { - node.Unmapped.Add(parameter); - } - } - - return node; + throw new CommandRuntimeException("Could not consume token when parsing command."); } - private void ParseString( - CommandTreeParserContext context, - CommandTreeTokenStream stream, - CommandTree node) + var command = current.FindCommand(commandToken.Value, CaseSensitivity); + if (command == null) { - if (context.State == State.Remaining) + throw CommandParseException.UnknownCommand(_configuration, parent, context.Arguments, commandToken); + } + + return ParseCommandParameters(context, command, parent, stream); + } + + private CommandTree ParseCommandParameters( + CommandTreeParserContext context, + CommandInfo command, + CommandTree? parent, + CommandTreeTokenStream stream) + { + context.ResetArgumentPosition(); + + var node = new CommandTree(parent, command); + while (stream.Peek() != null) + { + var token = stream.Peek(); + if (token == null) { - stream.Consume(CommandTreeToken.Kind.String); - return; + // Should not happen, but the compiler isn't + // smart enough to realize this... + throw new CommandRuntimeException("Could not get the next token."); } - var token = stream.Expect(CommandTreeToken.Kind.String); - - // Command? - var command = node.Command.FindCommand(token.Value, CaseSensitivity); - if (command != null) + switch (token.TokenKind) { - if (context.State == State.Normal) - { - node.Next = ParseCommand(context, node.Command, node, stream); - } + case CommandTreeToken.Kind.LongOption: + // Long option + ParseOption(context, stream, token, node, true); + break; + case CommandTreeToken.Kind.ShortOption: + // Short option + ParseOption(context, stream, token, node, false); + break; + case CommandTreeToken.Kind.String: + // Command + ParseString(context, stream, node); + break; + case CommandTreeToken.Kind.Remaining: + // Remaining + stream.Consume(CommandTreeToken.Kind.Remaining); + context.State = State.Remaining; + break; + default: + throw new InvalidOperationException($"Encountered unknown token ({token.TokenKind})."); + } + } - return; + // Add unmapped parameters. + foreach (var parameter in node.Command.Parameters) + { + if (node.Mapped.All(m => m.Parameter != parameter)) + { + node.Unmapped.Add(parameter); + } + } + + return node; + } + + private void ParseString( + CommandTreeParserContext context, + CommandTreeTokenStream stream, + CommandTree node) + { + if (context.State == State.Remaining) + { + stream.Consume(CommandTreeToken.Kind.String); + return; + } + + var token = stream.Expect(CommandTreeToken.Kind.String); + + // Command? + var command = node.Command.FindCommand(token.Value, CaseSensitivity); + if (command != null) + { + if (context.State == State.Normal) + { + node.Next = ParseCommand(context, node.Command, node, stream); } - // Current command has no arguments? - if (!node.HasArguments()) + return; + } + + // Current command has no arguments? + if (!node.HasArguments()) + { + throw CommandParseException.UnknownCommand(_configuration, node, context.Arguments, token); + } + + // Argument? + var parameter = node.FindArgument(context.CurrentArgumentPosition); + if (parameter == null) + { + // No parameters left. Any commands after this? + if (node.Command.Children.Count > 0 || node.Command.IsDefaultCommand) { throw CommandParseException.UnknownCommand(_configuration, node, context.Arguments, token); } - // Argument? - var parameter = node.FindArgument(context.CurrentArgumentPosition); - if (parameter == null) - { - // No parameters left. Any commands after this? - if (node.Command.Children.Count > 0 || node.Command.IsDefaultCommand) - { - throw CommandParseException.UnknownCommand(_configuration, node, context.Arguments, token); - } - - throw CommandParseException.CouldNotMatchArgument(context.Arguments, token); - } - - // Yes, this was an argument. - if (parameter.ParameterKind == ParameterKind.Vector) - { - // Vector - var current = stream.Current; - while (current?.TokenKind == CommandTreeToken.Kind.String) - { - var value = stream.Consume(CommandTreeToken.Kind.String)?.Value; - node.Mapped.Add(new MappedCommandParameter(parameter, value)); - current = stream.Current; - } - } - else - { - // Scalar - var value = stream.Consume(CommandTreeToken.Kind.String)?.Value; - node.Mapped.Add(new MappedCommandParameter(parameter, value)); - context.IncreaseArgumentPosition(); - } + throw CommandParseException.CouldNotMatchArgument(context.Arguments, token); } - private void ParseOption( - CommandTreeParserContext context, - CommandTreeTokenStream stream, - CommandTreeToken token, - CommandTree node, - bool isLongOption) + // Yes, this was an argument. + if (parameter.ParameterKind == ParameterKind.Vector) { - // Consume the option token. - stream.Consume(isLongOption ? CommandTreeToken.Kind.LongOption : CommandTreeToken.Kind.ShortOption); - - if (context.State == State.Normal) + // Vector + var current = stream.Current; + while (current?.TokenKind == CommandTreeToken.Kind.String) { - // Find the option. - var option = node.FindOption(token.Value, isLongOption, CaseSensitivity); - if (option != null) - { - node.Mapped.Add(new MappedCommandParameter( - option, ParseOptionValue(context, stream, token, node, option))); - - return; - } - - // Help? - if (_help?.IsMatch(token.Value) == true) - { - node.ShowHelp = true; - return; - } + var value = stream.Consume(CommandTreeToken.Kind.String)?.Value; + node.Mapped.Add(new MappedCommandParameter(parameter, value)); + current = stream.Current; } + } + else + { + // Scalar + var value = stream.Consume(CommandTreeToken.Kind.String)?.Value; + node.Mapped.Add(new MappedCommandParameter(parameter, value)); + context.IncreaseArgumentPosition(); + } + } - if (context.State == State.Remaining) + private void ParseOption( + CommandTreeParserContext context, + CommandTreeTokenStream stream, + CommandTreeToken token, + CommandTree node, + bool isLongOption) + { + // Consume the option token. + stream.Consume(isLongOption ? CommandTreeToken.Kind.LongOption : CommandTreeToken.Kind.ShortOption); + + if (context.State == State.Normal) + { + // Find the option. + var option = node.FindOption(token.Value, isLongOption, CaseSensitivity); + if (option != null) { - ParseOptionValue(context, stream, token, node, null); + node.Mapped.Add(new MappedCommandParameter( + option, ParseOptionValue(context, stream, token, node, option))); + return; } - if (context.ParsingMode == ParsingMode.Strict) + // Help? + if (_help?.IsMatch(token.Value) == true) { - throw CommandParseException.UnknownOption(context.Arguments, token); - } - else - { - ParseOptionValue(context, stream, token, node, null); + node.ShowHelp = true; + return; } } - private string? ParseOptionValue( - CommandTreeParserContext context, - CommandTreeTokenStream stream, - CommandTreeToken token, - CommandTree current, - CommandParameter? parameter) + if (context.State == State.Remaining) { - var value = default(string); + ParseOptionValue(context, stream, token, node, null); + return; + } - // Parse the value of the token (if any). - var valueToken = stream.Peek(); - if (valueToken?.TokenKind == CommandTreeToken.Kind.String) + if (context.ParsingMode == ParsingMode.Strict) + { + throw CommandParseException.UnknownOption(context.Arguments, token); + } + else + { + ParseOptionValue(context, stream, token, node, null); + } + } + + private string? ParseOptionValue( + CommandTreeParserContext context, + CommandTreeTokenStream stream, + CommandTreeToken token, + CommandTree current, + CommandParameter? parameter) + { + var value = default(string); + + // Parse the value of the token (if any). + var valueToken = stream.Peek(); + if (valueToken?.TokenKind == CommandTreeToken.Kind.String) + { + var parseValue = true; + if (token.TokenKind == CommandTreeToken.Kind.ShortOption && token.IsGrouped) { - var parseValue = true; - if (token.TokenKind == CommandTreeToken.Kind.ShortOption && token.IsGrouped) - { - parseValue = false; - } - - if (context.State == State.Normal && parseValue) - { - // Is this a command? - if (current.Command.FindCommand(valueToken.Value, CaseSensitivity) == null) - { - if (parameter != null) - { - if (parameter.ParameterKind == ParameterKind.Flag) - { - if (!CliConstants.AcceptedBooleanValues.Contains(valueToken.Value, StringComparer.OrdinalIgnoreCase)) - { - // Flags cannot be assigned a value. - throw CommandParseException.CannotAssignValueToFlag(context.Arguments, token); - } - } - - value = stream.Consume(CommandTreeToken.Kind.String)?.Value; - } - else - { - // Unknown parameter value. - value = stream.Consume(CommandTreeToken.Kind.String)?.Value; - - // In relaxed parsing mode? - if (context.ParsingMode == ParsingMode.Relaxed) - { - context.AddRemainingArgument(token.Value, value); - } - } - } - } - else - { - context.AddRemainingArgument(token.Value, parseValue ? valueToken.Value : null); - } - } - else - { - if (context.State == State.Remaining || context.ParsingMode == ParsingMode.Relaxed) - { - context.AddRemainingArgument(token.Value, null); - } + parseValue = false; } - // No value? - if (context.State == State.Normal) + if (context.State == State.Normal && parseValue) { - if (value == null && parameter != null) + // Is this a command? + if (current.Command.FindCommand(valueToken.Value, CaseSensitivity) == null) { - if (parameter.ParameterKind == ParameterKind.Flag) + if (parameter != null) { - value = "true"; + if (parameter.ParameterKind == ParameterKind.Flag) + { + if (!CliConstants.AcceptedBooleanValues.Contains(valueToken.Value, StringComparer.OrdinalIgnoreCase)) + { + // Flags cannot be assigned a value. + throw CommandParseException.CannotAssignValueToFlag(context.Arguments, token); + } + } + + value = stream.Consume(CommandTreeToken.Kind.String)?.Value; } else { - if (parameter is CommandOption option) - { - if (parameter.IsFlagValue()) - { - return null; - } + // Unknown parameter value. + value = stream.Consume(CommandTreeToken.Kind.String)?.Value; - throw CommandParseException.OptionHasNoValue(context.Arguments, token, option); - } - else + // In relaxed parsing mode? + if (context.ParsingMode == ParsingMode.Relaxed) { - // This should not happen at all. If it does, it's because we've added a new - // option type which isn't a CommandOption for some reason. - throw new InvalidOperationException($"Found invalid parameter type '{parameter.GetType().FullName}'."); + context.AddRemainingArgument(token.Value, value); } } } } - - return value; + else + { + context.AddRemainingArgument(token.Value, parseValue ? valueToken.Value : null); + } } + else + { + if (context.State == State.Remaining || context.ParsingMode == ParsingMode.Relaxed) + { + context.AddRemainingArgument(token.Value, null); + } + } + + // No value? + if (context.State == State.Normal) + { + if (value == null && parameter != null) + { + if (parameter.ParameterKind == ParameterKind.Flag) + { + value = "true"; + } + else + { + if (parameter is CommandOption option) + { + if (parameter.IsFlagValue()) + { + return null; + } + + throw CommandParseException.OptionHasNoValue(context.Arguments, token, option); + } + else + { + // This should not happen at all. If it does, it's because we've added a new + // option type which isn't a CommandOption for some reason. + throw new InvalidOperationException($"Found invalid parameter type '{parameter.GetType().FullName}'."); + } + } + } + } + + return value; } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Parsing/CommandTreeParserContext.cs b/src/Spectre.Console/Cli/Internal/Parsing/CommandTreeParserContext.cs index 044b9f8..9d340fa 100644 --- a/src/Spectre.Console/Cli/Internal/Parsing/CommandTreeParserContext.cs +++ b/src/Spectre.Console/Cli/Internal/Parsing/CommandTreeParserContext.cs @@ -3,55 +3,54 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal class CommandTreeParserContext { - internal class CommandTreeParserContext + private readonly List _args; + private readonly Dictionary> _remaining; + + public IReadOnlyList Arguments => _args; + public int CurrentArgumentPosition { get; private set; } + public CommandTreeParser.State State { get; set; } + public ParsingMode ParsingMode { get; } + + public CommandTreeParserContext(IEnumerable args, ParsingMode parsingMode) { - private readonly List _args; - private readonly Dictionary> _remaining; + _args = new List(args); + _remaining = new Dictionary>(StringComparer.Ordinal); - public IReadOnlyList Arguments => _args; - public int CurrentArgumentPosition { get; private set; } - public CommandTreeParser.State State { get; set; } - public ParsingMode ParsingMode { get; } + ParsingMode = parsingMode; + } - public CommandTreeParserContext(IEnumerable args, ParsingMode parsingMode) + public void ResetArgumentPosition() + { + CurrentArgumentPosition = 0; + } + + public void IncreaseArgumentPosition() + { + CurrentArgumentPosition++; + } + + public void AddRemainingArgument(string key, string? value) + { + if (State == CommandTreeParser.State.Remaining || ParsingMode == ParsingMode.Relaxed) { - _args = new List(args); - _remaining = new Dictionary>(StringComparer.Ordinal); - - ParsingMode = parsingMode; - } - - public void ResetArgumentPosition() - { - CurrentArgumentPosition = 0; - } - - public void IncreaseArgumentPosition() - { - CurrentArgumentPosition++; - } - - public void AddRemainingArgument(string key, string? value) - { - if (State == CommandTreeParser.State.Remaining || ParsingMode == ParsingMode.Relaxed) + if (!_remaining.ContainsKey(key)) { - if (!_remaining.ContainsKey(key)) - { - _remaining.Add(key, new List()); - } - - _remaining[key].Add(value); + _remaining.Add(key, new List()); } - } - [SuppressMessage("Style", "IDE0004:Remove Unnecessary Cast", Justification = "Bug in analyzer?")] - public ILookup GetRemainingArguments() - { - return _remaining - .SelectMany(pair => pair.Value, (pair, value) => new { pair.Key, value }) - .ToLookup(pair => pair.Key, pair => (string?)pair.value); + _remaining[key].Add(value); } } + + [SuppressMessage("Style", "IDE0004:Remove Unnecessary Cast", Justification = "Bug in analyzer?")] + public ILookup GetRemainingArguments() + { + return _remaining + .SelectMany(pair => pair.Value, (pair, value) => new { pair.Key, value }) + .ToLookup(pair => pair.Key, pair => (string?)pair.value); + } } \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Parsing/CommandTreeParserResult.cs b/src/Spectre.Console/Cli/Internal/Parsing/CommandTreeParserResult.cs index 0a2e8af..3e5213f 100644 --- a/src/Spectre.Console/Cli/Internal/Parsing/CommandTreeParserResult.cs +++ b/src/Spectre.Console/Cli/Internal/Parsing/CommandTreeParserResult.cs @@ -1,15 +1,14 @@ -namespace Spectre.Console.Cli -{ - // Consider removing this in favor for value tuples at some point. - internal sealed class CommandTreeParserResult - { - public CommandTree? Tree { get; } - public IRemainingArguments Remaining { get; } +namespace Spectre.Console.Cli; - public CommandTreeParserResult(CommandTree? tree, IRemainingArguments remaining) - { - Tree = tree; - Remaining = remaining; - } +// Consider removing this in favor for value tuples at some point. +internal sealed class CommandTreeParserResult +{ + public CommandTree? Tree { get; } + public IRemainingArguments Remaining { get; } + + public CommandTreeParserResult(CommandTree? tree, IRemainingArguments remaining) + { + Tree = tree; + Remaining = remaining; } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Parsing/CommandTreeToken.cs b/src/Spectre.Console/Cli/Internal/Parsing/CommandTreeToken.cs index 5ed8a16..189792e 100644 --- a/src/Spectre.Console/Cli/Internal/Parsing/CommandTreeToken.cs +++ b/src/Spectre.Console/Cli/Internal/Parsing/CommandTreeToken.cs @@ -1,27 +1,26 @@ -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal sealed class CommandTreeToken { - internal sealed class CommandTreeToken + public Kind TokenKind { get; } + public int Position { get; } + public string Value { get; } + public string Representation { get; } + public bool IsGrouped { get; set; } + + public enum Kind { - public Kind TokenKind { get; } - public int Position { get; } - public string Value { get; } - public string Representation { get; } - public bool IsGrouped { get; set; } - - public enum Kind - { - String, - LongOption, - ShortOption, - Remaining, - } - - public CommandTreeToken(Kind kind, int position, string value, string representation) - { - TokenKind = kind; - Position = position; - Value = value; - Representation = representation; - } + String, + LongOption, + ShortOption, + Remaining, } -} + + public CommandTreeToken(Kind kind, int position, string value, string representation) + { + TokenKind = kind; + Position = position; + Value = value; + Representation = representation; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Parsing/CommandTreeTokenStream.cs b/src/Spectre.Console/Cli/Internal/Parsing/CommandTreeTokenStream.cs index 6322ecd..9e42250 100644 --- a/src/Spectre.Console/Cli/Internal/Parsing/CommandTreeTokenStream.cs +++ b/src/Spectre.Console/Cli/Internal/Parsing/CommandTreeTokenStream.cs @@ -2,89 +2,88 @@ using System.Collections; using System.Collections.Generic; using System.Linq; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal sealed class CommandTreeTokenStream : IReadOnlyList { - internal sealed class CommandTreeTokenStream : IReadOnlyList + private readonly List _tokens; + private int _position; + + public int Count => _tokens.Count; + + public CommandTreeToken this[int index] => _tokens[index]; + + public CommandTreeToken? Current { - private readonly List _tokens; - private int _position; - - public int Count => _tokens.Count; - - public CommandTreeToken this[int index] => _tokens[index]; - - public CommandTreeToken? Current - { - get - { - if (_position >= Count) - { - return null; - } - - return _tokens[_position]; - } - } - - public CommandTreeTokenStream(IEnumerable tokens) - { - _tokens = new List(tokens ?? Enumerable.Empty()); - _position = 0; - } - - public CommandTreeToken? Peek(int index = 0) - { - var position = _position + index; - if (position >= Count) - { - return null; - } - - return _tokens[position]; - } - - public CommandTreeToken? Consume() + get { if (_position >= Count) { return null; } - var token = _tokens[_position]; - _position++; - return token; - } - - public CommandTreeToken? Consume(CommandTreeToken.Kind type) - { - Expect(type); - return Consume(); - } - - public CommandTreeToken Expect(CommandTreeToken.Kind expected) - { - if (Current == null) - { - throw CommandParseException.ExpectedTokenButFoundNull(expected); - } - - var found = Current.TokenKind; - if (expected != found) - { - throw CommandParseException.ExpectedTokenButFoundOther(expected, found); - } - - return Current; - } - - public IEnumerator GetEnumerator() - { - return _tokens.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); + return _tokens[_position]; } } -} + + public CommandTreeTokenStream(IEnumerable tokens) + { + _tokens = new List(tokens ?? Enumerable.Empty()); + _position = 0; + } + + public CommandTreeToken? Peek(int index = 0) + { + var position = _position + index; + if (position >= Count) + { + return null; + } + + return _tokens[position]; + } + + public CommandTreeToken? Consume() + { + if (_position >= Count) + { + return null; + } + + var token = _tokens[_position]; + _position++; + return token; + } + + public CommandTreeToken? Consume(CommandTreeToken.Kind type) + { + Expect(type); + return Consume(); + } + + public CommandTreeToken Expect(CommandTreeToken.Kind expected) + { + if (Current == null) + { + throw CommandParseException.ExpectedTokenButFoundNull(expected); + } + + var found = Current.TokenKind; + if (expected != found) + { + throw CommandParseException.ExpectedTokenButFoundOther(expected, found); + } + + return Current; + } + + public IEnumerator GetEnumerator() + { + return _tokens.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Parsing/CommandTreeTokenizer.cs b/src/Spectre.Console/Cli/Internal/Parsing/CommandTreeTokenizer.cs index b27a421..dcb5621 100644 --- a/src/Spectre.Console/Cli/Internal/Parsing/CommandTreeTokenizer.cs +++ b/src/Spectre.Console/Cli/Internal/Parsing/CommandTreeTokenizer.cs @@ -3,303 +3,302 @@ using System.Globalization; using System.Linq; using System.Text; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal static class CommandTreeTokenizer { - internal static class CommandTreeTokenizer + public enum Mode { - public enum Mode + Normal = 0, + Remaining = 1, + } + + // Consider removing this in favor for value tuples at some point. + public sealed class CommandTreeTokenizerResult + { + public CommandTreeTokenStream Tokens { get; } + public IReadOnlyList Remaining { get; } + + public CommandTreeTokenizerResult(CommandTreeTokenStream tokens, IReadOnlyList remaining) { - Normal = 0, - Remaining = 1, - } - - // Consider removing this in favor for value tuples at some point. - public sealed class CommandTreeTokenizerResult - { - public CommandTreeTokenStream Tokens { get; } - public IReadOnlyList Remaining { get; } - - public CommandTreeTokenizerResult(CommandTreeTokenStream tokens, IReadOnlyList remaining) - { - Tokens = tokens; - Remaining = remaining; - } - } - - public static CommandTreeTokenizerResult Tokenize(IEnumerable args) - { - var tokens = new List(); - var position = 0; - var previousReader = default(TextBuffer); - var context = new CommandTreeTokenizerContext(); - - foreach (var arg in args) - { - var start = position; - var reader = new TextBuffer(previousReader, arg); - - // Parse the token. - position = ParseToken(context, reader, position, start, tokens); - context.FlushRemaining(); - - previousReader = reader; - } - - previousReader?.Dispose(); - - return new CommandTreeTokenizerResult( - new CommandTreeTokenStream(tokens), - context.Remaining); - } - - private static int ParseToken(CommandTreeTokenizerContext context, TextBuffer reader, int position, int start, List tokens) - { - while (reader.Peek() != -1) - { - if (reader.ReachedEnd) - { - position += reader.Position - start; - break; - } - - var character = reader.Peek(); - - // Eat whitespace - if (char.IsWhiteSpace(character)) - { - reader.Consume(); - continue; - } - - if (character == '-') - { - // Option - tokens.AddRange(ScanOptions(context, reader)); - } - else - { - // Command or argument - tokens.Add(ScanString(context, reader)); - } - - // Flush remaining tokens - context.FlushRemaining(); - } - - return position; - } - - private static CommandTreeToken ScanString( - CommandTreeTokenizerContext context, - TextBuffer reader, - char[]? stop = null) - { - if (reader.TryPeek(out var character)) - { - // Is this a quoted string? - if (character == '\"') - { - return ScanQuotedString(context, reader); - } - } - - var position = reader.Position; - var builder = new StringBuilder(); - while (!reader.ReachedEnd) - { - var current = reader.Peek(); - if (stop?.Contains(current) ?? false) - { - break; - } - - reader.Read(); // Consume - context.AddRemaining(current); - builder.Append(current); - } - - var value = builder.ToString(); - return new CommandTreeToken(CommandTreeToken.Kind.String, position, value.Trim(), value); - } - - private static CommandTreeToken ScanQuotedString(CommandTreeTokenizerContext context, TextBuffer reader) - { - var position = reader.Position; - - context.FlushRemaining(); - reader.Consume('\"'); - - var builder = new StringBuilder(); - var terminated = false; - while (!reader.ReachedEnd) - { - var character = reader.Peek(); - if (character == '\"') - { - terminated = true; - reader.Read(); - break; - } - - builder.Append(reader.Read()); - } - - if (!terminated) - { - var unterminatedQuote = builder.ToString(); - var token = new CommandTreeToken(CommandTreeToken.Kind.String, position, unterminatedQuote, $"\"{unterminatedQuote}"); - throw CommandParseException.UnterminatedQuote(reader.Original, token); - } - - var quotedString = builder.ToString(); - - // Add to the context - context.AddRemaining(quotedString); - - return new CommandTreeToken( - CommandTreeToken.Kind.String, - position, quotedString, - quotedString); - } - - private static IEnumerable ScanOptions(CommandTreeTokenizerContext context, TextBuffer reader) - { - var result = new List(); - - var position = reader.Position; - - reader.Consume('-'); - context.AddRemaining('-'); - - if (!reader.TryPeek(out var character)) - { - var token = new CommandTreeToken(CommandTreeToken.Kind.ShortOption, position, "-", "-"); - throw CommandParseException.OptionHasNoName(reader.Original, token); - } - - switch (character) - { - case '-': - var option = ScanLongOption(context, reader, position); - if (option != null) - { - result.Add(option); - } - - break; - default: - result.AddRange(ScanShortOptions(context, reader, position)); - break; - } - - if (reader.TryPeek(out character)) - { - // Encountered a separator? - if (character == '=' || character == ':') - { - reader.Read(); // Consume - context.AddRemaining(character); - - if (!reader.TryPeek(out _)) - { - var token = new CommandTreeToken(CommandTreeToken.Kind.String, reader.Position, "=", "="); - throw CommandParseException.OptionValueWasExpected(reader.Original, token); - } - - result.Add(ScanString(context, reader)); - } - } - - return result; - } - - private static IEnumerable ScanShortOptions(CommandTreeTokenizerContext context, TextBuffer reader, int position) - { - var result = new List(); - while (!reader.ReachedEnd) - { - var current = reader.Peek(); - if (char.IsWhiteSpace(current)) - { - break; - } - - // Encountered a separator? - if (current == '=' || current == ':') - { - break; - } - - if (char.IsLetter(current)) - { - context.AddRemaining(current); - reader.Read(); // Consume - - var value = current.ToString(CultureInfo.InvariantCulture); - result.Add(result.Count == 0 - ? new CommandTreeToken(CommandTreeToken.Kind.ShortOption, position, value, $"-{value}") - : new CommandTreeToken(CommandTreeToken.Kind.ShortOption, position + result.Count, value, value)); - } - else - { - // Create a token representing the short option. - var tokenPosition = position + 1 + result.Count; - var represntation = current.ToString(CultureInfo.InvariantCulture); - var token = new CommandTreeToken(CommandTreeToken.Kind.ShortOption, tokenPosition, represntation, represntation); - throw CommandParseException.InvalidShortOptionName(reader.Original, token); - } - } - - if (result.Count > 1) - { - foreach (var item in result) - { - item.IsGrouped = true; - } - } - - return result; - } - - private static CommandTreeToken ScanLongOption(CommandTreeTokenizerContext context, TextBuffer reader, int position) - { - reader.Consume('-'); - context.AddRemaining('-'); - - if (reader.ReachedEnd) - { - // Rest of the arguments are remaining ones. - context.Mode = Mode.Remaining; - return new CommandTreeToken(CommandTreeToken.Kind.Remaining, position, "--", "--"); - } - - var name = ScanString(context, reader, new[] { '=', ':' }); - - // Perform validation of the name. - if (name.Value.Length == 0) - { - throw CommandParseException.LongOptionNameIsMissing(reader, position); - } - - if (name.Value.Length == 1) - { - throw CommandParseException.LongOptionNameIsOneCharacter(reader, position, name.Value); - } - - if (char.IsDigit(name.Value[0])) - { - throw CommandParseException.LongOptionNameStartWithDigit(reader, position, name.Value); - } - - for (var index = 0; index < name.Value.Length; index++) - { - if (!char.IsLetterOrDigit(name.Value[index]) && name.Value[index] != '-' && name.Value[index] != '_') - { - throw CommandParseException.LongOptionNameContainSymbol(reader, position + 2 + index, name.Value[index]); - } - } - - return new CommandTreeToken(CommandTreeToken.Kind.LongOption, position, name.Value, $"--{name.Value}"); + Tokens = tokens; + Remaining = remaining; } } -} + + public static CommandTreeTokenizerResult Tokenize(IEnumerable args) + { + var tokens = new List(); + var position = 0; + var previousReader = default(TextBuffer); + var context = new CommandTreeTokenizerContext(); + + foreach (var arg in args) + { + var start = position; + var reader = new TextBuffer(previousReader, arg); + + // Parse the token. + position = ParseToken(context, reader, position, start, tokens); + context.FlushRemaining(); + + previousReader = reader; + } + + previousReader?.Dispose(); + + return new CommandTreeTokenizerResult( + new CommandTreeTokenStream(tokens), + context.Remaining); + } + + private static int ParseToken(CommandTreeTokenizerContext context, TextBuffer reader, int position, int start, List tokens) + { + while (reader.Peek() != -1) + { + if (reader.ReachedEnd) + { + position += reader.Position - start; + break; + } + + var character = reader.Peek(); + + // Eat whitespace + if (char.IsWhiteSpace(character)) + { + reader.Consume(); + continue; + } + + if (character == '-') + { + // Option + tokens.AddRange(ScanOptions(context, reader)); + } + else + { + // Command or argument + tokens.Add(ScanString(context, reader)); + } + + // Flush remaining tokens + context.FlushRemaining(); + } + + return position; + } + + private static CommandTreeToken ScanString( + CommandTreeTokenizerContext context, + TextBuffer reader, + char[]? stop = null) + { + if (reader.TryPeek(out var character)) + { + // Is this a quoted string? + if (character == '\"') + { + return ScanQuotedString(context, reader); + } + } + + var position = reader.Position; + var builder = new StringBuilder(); + while (!reader.ReachedEnd) + { + var current = reader.Peek(); + if (stop?.Contains(current) ?? false) + { + break; + } + + reader.Read(); // Consume + context.AddRemaining(current); + builder.Append(current); + } + + var value = builder.ToString(); + return new CommandTreeToken(CommandTreeToken.Kind.String, position, value.Trim(), value); + } + + private static CommandTreeToken ScanQuotedString(CommandTreeTokenizerContext context, TextBuffer reader) + { + var position = reader.Position; + + context.FlushRemaining(); + reader.Consume('\"'); + + var builder = new StringBuilder(); + var terminated = false; + while (!reader.ReachedEnd) + { + var character = reader.Peek(); + if (character == '\"') + { + terminated = true; + reader.Read(); + break; + } + + builder.Append(reader.Read()); + } + + if (!terminated) + { + var unterminatedQuote = builder.ToString(); + var token = new CommandTreeToken(CommandTreeToken.Kind.String, position, unterminatedQuote, $"\"{unterminatedQuote}"); + throw CommandParseException.UnterminatedQuote(reader.Original, token); + } + + var quotedString = builder.ToString(); + + // Add to the context + context.AddRemaining(quotedString); + + return new CommandTreeToken( + CommandTreeToken.Kind.String, + position, quotedString, + quotedString); + } + + private static IEnumerable ScanOptions(CommandTreeTokenizerContext context, TextBuffer reader) + { + var result = new List(); + + var position = reader.Position; + + reader.Consume('-'); + context.AddRemaining('-'); + + if (!reader.TryPeek(out var character)) + { + var token = new CommandTreeToken(CommandTreeToken.Kind.ShortOption, position, "-", "-"); + throw CommandParseException.OptionHasNoName(reader.Original, token); + } + + switch (character) + { + case '-': + var option = ScanLongOption(context, reader, position); + if (option != null) + { + result.Add(option); + } + + break; + default: + result.AddRange(ScanShortOptions(context, reader, position)); + break; + } + + if (reader.TryPeek(out character)) + { + // Encountered a separator? + if (character == '=' || character == ':') + { + reader.Read(); // Consume + context.AddRemaining(character); + + if (!reader.TryPeek(out _)) + { + var token = new CommandTreeToken(CommandTreeToken.Kind.String, reader.Position, "=", "="); + throw CommandParseException.OptionValueWasExpected(reader.Original, token); + } + + result.Add(ScanString(context, reader)); + } + } + + return result; + } + + private static IEnumerable ScanShortOptions(CommandTreeTokenizerContext context, TextBuffer reader, int position) + { + var result = new List(); + while (!reader.ReachedEnd) + { + var current = reader.Peek(); + if (char.IsWhiteSpace(current)) + { + break; + } + + // Encountered a separator? + if (current == '=' || current == ':') + { + break; + } + + if (char.IsLetter(current)) + { + context.AddRemaining(current); + reader.Read(); // Consume + + var value = current.ToString(CultureInfo.InvariantCulture); + result.Add(result.Count == 0 + ? new CommandTreeToken(CommandTreeToken.Kind.ShortOption, position, value, $"-{value}") + : new CommandTreeToken(CommandTreeToken.Kind.ShortOption, position + result.Count, value, value)); + } + else + { + // Create a token representing the short option. + var tokenPosition = position + 1 + result.Count; + var represntation = current.ToString(CultureInfo.InvariantCulture); + var token = new CommandTreeToken(CommandTreeToken.Kind.ShortOption, tokenPosition, represntation, represntation); + throw CommandParseException.InvalidShortOptionName(reader.Original, token); + } + } + + if (result.Count > 1) + { + foreach (var item in result) + { + item.IsGrouped = true; + } + } + + return result; + } + + private static CommandTreeToken ScanLongOption(CommandTreeTokenizerContext context, TextBuffer reader, int position) + { + reader.Consume('-'); + context.AddRemaining('-'); + + if (reader.ReachedEnd) + { + // Rest of the arguments are remaining ones. + context.Mode = Mode.Remaining; + return new CommandTreeToken(CommandTreeToken.Kind.Remaining, position, "--", "--"); + } + + var name = ScanString(context, reader, new[] { '=', ':' }); + + // Perform validation of the name. + if (name.Value.Length == 0) + { + throw CommandParseException.LongOptionNameIsMissing(reader, position); + } + + if (name.Value.Length == 1) + { + throw CommandParseException.LongOptionNameIsOneCharacter(reader, position, name.Value); + } + + if (char.IsDigit(name.Value[0])) + { + throw CommandParseException.LongOptionNameStartWithDigit(reader, position, name.Value); + } + + for (var index = 0; index < name.Value.Length; index++) + { + if (!char.IsLetterOrDigit(name.Value[index]) && name.Value[index] != '-' && name.Value[index] != '_') + { + throw CommandParseException.LongOptionNameContainSymbol(reader, position + 2 + index, name.Value[index]); + } + } + + return new CommandTreeToken(CommandTreeToken.Kind.LongOption, position, name.Value, $"--{name.Value}"); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/Parsing/CommandTreeTokenizerContext.cs b/src/Spectre.Console/Cli/Internal/Parsing/CommandTreeTokenizerContext.cs index d4c7f61..0e1fb3d 100644 --- a/src/Spectre.Console/Cli/Internal/Parsing/CommandTreeTokenizerContext.cs +++ b/src/Spectre.Console/Cli/Internal/Parsing/CommandTreeTokenizerContext.cs @@ -1,47 +1,46 @@ using System.Collections.Generic; using System.Text; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal sealed class CommandTreeTokenizerContext { - internal sealed class CommandTreeTokenizerContext + private readonly StringBuilder _builder; + private readonly List _remaining; + + public CommandTreeTokenizer.Mode Mode { get; set; } + public IReadOnlyList Remaining => _remaining; + + public CommandTreeTokenizerContext() { - private readonly StringBuilder _builder; - private readonly List _remaining; + _builder = new StringBuilder(); + _remaining = new List(); + } - public CommandTreeTokenizer.Mode Mode { get; set; } - public IReadOnlyList Remaining => _remaining; - - public CommandTreeTokenizerContext() + public void AddRemaining(char character) + { + if (Mode == CommandTreeTokenizer.Mode.Remaining) { - _builder = new StringBuilder(); - _remaining = new List(); + _builder.Append(character); } + } - public void AddRemaining(char character) + public void AddRemaining(string text) + { + if (Mode == CommandTreeTokenizer.Mode.Remaining) { - if (Mode == CommandTreeTokenizer.Mode.Remaining) - { - _builder.Append(character); - } + _builder.Append(text); } + } - public void AddRemaining(string text) + public void FlushRemaining() + { + if (Mode == CommandTreeTokenizer.Mode.Remaining) { - if (Mode == CommandTreeTokenizer.Mode.Remaining) + if (_builder.Length > 0) { - _builder.Append(text); - } - } - - public void FlushRemaining() - { - if (Mode == CommandTreeTokenizer.Mode.Remaining) - { - if (_builder.Length > 0) - { - _remaining.Add(_builder.ToString()); - _builder.Clear(); - } + _remaining.Add(_builder.ToString()); + _builder.Clear(); } } } diff --git a/src/Spectre.Console/Cli/Internal/Parsing/MappedCommandParameter.cs b/src/Spectre.Console/Cli/Internal/Parsing/MappedCommandParameter.cs index b68b385..0cd98fb 100644 --- a/src/Spectre.Console/Cli/Internal/Parsing/MappedCommandParameter.cs +++ b/src/Spectre.Console/Cli/Internal/Parsing/MappedCommandParameter.cs @@ -1,15 +1,14 @@ -namespace Spectre.Console.Cli -{ - // Consider removing this in favor for value tuples at some point. - internal sealed class MappedCommandParameter - { - public CommandParameter Parameter { get; } - public string? Value { get; } +namespace Spectre.Console.Cli; - public MappedCommandParameter(CommandParameter parameter, string? value) - { - Parameter = parameter; - Value = value; - } +// Consider removing this in favor for value tuples at some point. +internal sealed class MappedCommandParameter +{ + public CommandParameter Parameter { get; } + public string? Value { get; } + + public MappedCommandParameter(CommandParameter parameter, string? value) + { + Parameter = parameter; + Value = value; } } \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/ParsingMode.cs b/src/Spectre.Console/Cli/Internal/ParsingMode.cs index 78abbfe..ab5ca4e 100644 --- a/src/Spectre.Console/Cli/Internal/ParsingMode.cs +++ b/src/Spectre.Console/Cli/Internal/ParsingMode.cs @@ -1,8 +1,7 @@ -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal enum ParsingMode { - internal enum ParsingMode - { - Relaxed = 0, - Strict = 1, - } -} + Relaxed = 0, + Strict = 1, +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/RemainingArguments.cs b/src/Spectre.Console/Cli/Internal/RemainingArguments.cs index dafeec1..25ec4fe 100644 --- a/src/Spectre.Console/Cli/Internal/RemainingArguments.cs +++ b/src/Spectre.Console/Cli/Internal/RemainingArguments.cs @@ -1,19 +1,18 @@ using System.Collections.Generic; using System.Linq; -namespace Spectre.Console.Cli -{ - internal sealed class RemainingArguments : IRemainingArguments - { - public IReadOnlyList Raw { get; } - public ILookup Parsed { get; } +namespace Spectre.Console.Cli; - public RemainingArguments( - ILookup remaining, - IReadOnlyList raw) - { - Parsed = remaining; - Raw = raw; - } +internal sealed class RemainingArguments : IRemainingArguments +{ + public IReadOnlyList Raw { get; } + public ILookup Parsed { get; } + + public RemainingArguments( + ILookup remaining, + IReadOnlyList raw) + { + Parsed = remaining; + Raw = raw; } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/StringWriterWithEncoding.cs b/src/Spectre.Console/Cli/Internal/StringWriterWithEncoding.cs index 948ea26..7ddc846 100644 --- a/src/Spectre.Console/Cli/Internal/StringWriterWithEncoding.cs +++ b/src/Spectre.Console/Cli/Internal/StringWriterWithEncoding.cs @@ -2,15 +2,14 @@ using System; using System.IO; using System.Text; -namespace Spectre.Console.Cli -{ - internal sealed class StringWriterWithEncoding : StringWriter - { - public override Encoding Encoding { get; } +namespace Spectre.Console.Cli; - public StringWriterWithEncoding(Encoding encoding) - { - Encoding = encoding ?? throw new ArgumentNullException(nameof(encoding)); - } +internal sealed class StringWriterWithEncoding : StringWriter +{ + public override Encoding Encoding { get; } + + public StringWriterWithEncoding(Encoding encoding) + { + Encoding = encoding ?? throw new ArgumentNullException(nameof(encoding)); } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/TextBuffer.cs b/src/Spectre.Console/Cli/Internal/TextBuffer.cs index 9490e53..45cb663 100644 --- a/src/Spectre.Console/Cli/Internal/TextBuffer.cs +++ b/src/Spectre.Console/Cli/Internal/TextBuffer.cs @@ -1,93 +1,92 @@ using System; using System.IO; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal sealed class TextBuffer : IDisposable { - internal sealed class TextBuffer : IDisposable + // There is some kind of bug + private readonly StringReader _reader; + + public bool ReachedEnd => _reader.Peek() == -1; + public string Original { get; } + public int Position { get; private set; } + + public TextBuffer(string text) { - // There is some kind of bug - private readonly StringReader _reader; + _reader = new StringReader(text); + Original = text; + Position = 0; + } - public bool ReachedEnd => _reader.Peek() == -1; - public string Original { get; } - public int Position { get; private set; } + public TextBuffer(TextBuffer? buffer, string text) + { + _reader = new StringReader(text); + Original = buffer != null ? buffer.Original + " " + text : text; + Position = buffer?.Position + 1 ?? 0; + } - public TextBuffer(string text) + public void Dispose() + { + _reader.Dispose(); + } + + public char Peek() + { + return (char)_reader.Peek(); + } + + public bool TryPeek(out char character) + { + var value = _reader.Peek(); + if (value == -1) { - _reader = new StringReader(text); - Original = text; - Position = 0; - } - - public TextBuffer(TextBuffer? buffer, string text) - { - _reader = new StringReader(text); - Original = buffer != null ? buffer.Original + " " + text : text; - Position = buffer?.Position + 1 ?? 0; - } - - public void Dispose() - { - _reader.Dispose(); - } - - public char Peek() - { - return (char)_reader.Peek(); - } - - public bool TryPeek(out char character) - { - var value = _reader.Peek(); - if (value == -1) - { - character = '\0'; - return false; - } - - character = (char)value; - return true; - } - - public void Consume() - { - EnsureNotAtEnd(); - Read(); - } - - public void Consume(char character) - { - EnsureNotAtEnd(); - if (Read() != character) - { - throw new InvalidOperationException($"Expected '{character}' token."); - } - } - - public bool IsNext(char character) - { - if (TryPeek(out var result)) - { - return result == character; - } - + character = '\0'; return false; } - public char Read() - { - EnsureNotAtEnd(); - var result = (char)_reader.Read(); - Position++; - return result; - } + character = (char)value; + return true; + } - private void EnsureNotAtEnd() + public void Consume() + { + EnsureNotAtEnd(); + Read(); + } + + public void Consume(char character) + { + EnsureNotAtEnd(); + if (Read() != character) { - if (ReachedEnd) - { - throw new InvalidOperationException("Can't read past the end of the buffer."); - } + throw new InvalidOperationException($"Expected '{character}' token."); } } -} + + public bool IsNext(char character) + { + if (TryPeek(out var result)) + { + return result == character; + } + + return false; + } + + public char Read() + { + EnsureNotAtEnd(); + var result = (char)_reader.Read(); + Position++; + return result; + } + + private void EnsureNotAtEnd() + { + if (ReachedEnd) + { + throw new InvalidOperationException("Can't read past the end of the buffer."); + } + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/TypeRegistrar.cs b/src/Spectre.Console/Cli/Internal/TypeRegistrar.cs index 201c104..5a3548c 100644 --- a/src/Spectre.Console/Cli/Internal/TypeRegistrar.cs +++ b/src/Spectre.Console/Cli/Internal/TypeRegistrar.cs @@ -1,41 +1,40 @@ using System; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal sealed class TypeRegistrar : ITypeRegistrarFrontend { - internal sealed class TypeRegistrar : ITypeRegistrarFrontend + private readonly ITypeRegistrar _registrar; + + internal TypeRegistrar(ITypeRegistrar registrar) { - private readonly ITypeRegistrar _registrar; - - internal TypeRegistrar(ITypeRegistrar registrar) - { - _registrar = registrar ?? throw new ArgumentNullException(nameof(registrar)); - } - - public void Register() - where TImplementation : TService - { - _registrar.Register(typeof(TService), typeof(TImplementation)); - } - - public void RegisterInstance(TImplementation instance) - { - if (instance == null) - { - throw new ArgumentNullException(nameof(instance)); - } - - _registrar.RegisterInstance(typeof(TImplementation), instance); - } - - public void RegisterInstance(TImplementation instance) - where TImplementation : TService - { - if (instance == null) - { - throw new ArgumentNullException(nameof(instance)); - } - - _registrar.RegisterInstance(typeof(TService), instance); - } + _registrar = registrar ?? throw new ArgumentNullException(nameof(registrar)); } -} + + public void Register() + where TImplementation : TService + { + _registrar.Register(typeof(TService), typeof(TImplementation)); + } + + public void RegisterInstance(TImplementation instance) + { + if (instance == null) + { + throw new ArgumentNullException(nameof(instance)); + } + + _registrar.RegisterInstance(typeof(TImplementation), instance); + } + + public void RegisterInstance(TImplementation instance) + where TImplementation : TService + { + if (instance == null) + { + throw new ArgumentNullException(nameof(instance)); + } + + _registrar.RegisterInstance(typeof(TService), instance); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/TypeResolverAdapter.cs b/src/Spectre.Console/Cli/Internal/TypeResolverAdapter.cs index 6dd5d98..62d5b0c 100644 --- a/src/Spectre.Console/Cli/Internal/TypeResolverAdapter.cs +++ b/src/Spectre.Console/Cli/Internal/TypeResolverAdapter.cs @@ -1,50 +1,49 @@ using System; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal sealed class TypeResolverAdapter : ITypeResolver, IDisposable { - internal sealed class TypeResolverAdapter : ITypeResolver, IDisposable + private readonly ITypeResolver? _resolver; + + public TypeResolverAdapter(ITypeResolver? resolver) { - private readonly ITypeResolver? _resolver; + _resolver = resolver; + } - public TypeResolverAdapter(ITypeResolver? resolver) + public object? Resolve(Type? type) + { + if (type == null) { - _resolver = resolver; + throw new CommandRuntimeException("Cannot resolve null type."); } - public object? Resolve(Type? type) + try { - if (type == null) + var obj = _resolver?.Resolve(type); + if (obj != null) { - throw new CommandRuntimeException("Cannot resolve null type."); + return obj; } - try - { - var obj = _resolver?.Resolve(type); - if (obj != null) - { - return obj; - } - - // Fall back to use the activator. - return Activator.CreateInstance(type); - } - catch (CommandAppException) - { - throw; - } - catch (Exception ex) - { - throw CommandRuntimeException.CouldNotResolveType(type, ex); - } + // Fall back to use the activator. + return Activator.CreateInstance(type); } - - public void Dispose() + catch (CommandAppException) { - if (_resolver is IDisposable disposable) - { - disposable.Dispose(); - } + throw; + } + catch (Exception ex) + { + throw CommandRuntimeException.CouldNotResolveType(type, ex); } } -} + + public void Dispose() + { + if (_resolver is IDisposable disposable) + { + disposable.Dispose(); + } + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Internal/VersionHelper.cs b/src/Spectre.Console/Cli/Internal/VersionHelper.cs index ddcd790..dc7f37f 100644 --- a/src/Spectre.Console/Cli/Internal/VersionHelper.cs +++ b/src/Spectre.Console/Cli/Internal/VersionHelper.cs @@ -1,14 +1,13 @@ using System.Reflection; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +internal static class VersionHelper { - internal static class VersionHelper + public static string GetVersion(Assembly? assembly) { - public static string GetVersion(Assembly? assembly) - { - return assembly? - .GetCustomAttribute()? - .InformationalVersion ?? "?"; - } + return assembly? + .GetCustomAttribute()? + .InformationalVersion ?? "?"; } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/PairDeconstructor.cs b/src/Spectre.Console/Cli/PairDeconstructor.cs index 163a85a..3cbdae3 100644 --- a/src/Spectre.Console/Cli/PairDeconstructor.cs +++ b/src/Spectre.Console/Cli/PairDeconstructor.cs @@ -1,41 +1,40 @@ using System; -namespace Spectre.Console.Cli +namespace Spectre.Console.Cli; + +/// +/// Base class for a pair deconstructor. +/// +/// The key type. +/// The value type. +public abstract class PairDeconstructor : IPairDeconstructor { /// - /// Base class for a pair deconstructor. + /// Deconstructs the provided into a pair. /// - /// The key type. - /// The value type. - public abstract class PairDeconstructor : IPairDeconstructor - { - /// - /// Deconstructs the provided into a pair. - /// - /// The string to deconstruct into a pair. - /// The deconstructed pair. - protected abstract (TKey Key, TValue Value) Deconstruct(string? value); + /// The string to deconstruct into a pair. + /// The deconstructed pair. + protected abstract (TKey Key, TValue Value) Deconstruct(string? value); - /// - (object? Key, object? Value) IPairDeconstructor.Deconstruct(ITypeResolver resolver, Type keyType, Type valueType, string? value) + /// + (object? Key, object? Value) IPairDeconstructor.Deconstruct(ITypeResolver resolver, Type keyType, Type valueType, string? value) + { + if (!keyType.IsAssignableFrom(typeof(TKey)) || !valueType.IsAssignableFrom(typeof(TValue))) { - if (!keyType.IsAssignableFrom(typeof(TKey)) || !valueType.IsAssignableFrom(typeof(TValue))) - { - throw new InvalidOperationException("Pair destructor is not compatible."); - } - - return Deconstruct(value); + throw new InvalidOperationException("Pair destructor is not compatible."); } - } - /// - /// Base class for a pair deconstructor. - /// - /// The key type. - /// The value type. - /// This class is misspelled, use instead. - [Obsolete("Use PairDeconstructor instead")] - public abstract class PairDeconstuctor : PairDeconstructor - { + return Deconstruct(value); } } + +/// +/// Base class for a pair deconstructor. +/// +/// The key type. +/// The value type. +/// This class is misspelled, use instead. +[Obsolete("Use PairDeconstructor instead")] +public abstract class PairDeconstuctor : PairDeconstructor +{ +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Unsafe/IUnsafeBranchConfigurator.cs b/src/Spectre.Console/Cli/Unsafe/IUnsafeBranchConfigurator.cs index 03ae985..29c6d41 100644 --- a/src/Spectre.Console/Cli/Unsafe/IUnsafeBranchConfigurator.cs +++ b/src/Spectre.Console/Cli/Unsafe/IUnsafeBranchConfigurator.cs @@ -1,20 +1,19 @@ -namespace Spectre.Console.Cli.Unsafe +namespace Spectre.Console.Cli.Unsafe; + +/// +/// Represents an unsafe configurator for a branch. +/// +public interface IUnsafeBranchConfigurator : IUnsafeConfigurator { /// - /// Represents an unsafe configurator for a branch. + /// Sets the description of the branch. /// - public interface IUnsafeBranchConfigurator : IUnsafeConfigurator - { - /// - /// Sets the description of the branch. - /// - /// The description of the branch. - void SetDescription(string description); + /// The description of the branch. + void SetDescription(string description); - /// - /// Adds an example of how to use the branch. - /// - /// The example arguments. - void AddExample(string[] args); - } -} + /// + /// Adds an example of how to use the branch. + /// + /// The example arguments. + void AddExample(string[] args); +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Unsafe/IUnsafeConfigurator.cs b/src/Spectre.Console/Cli/Unsafe/IUnsafeConfigurator.cs index 5aad769..f2b7633 100644 --- a/src/Spectre.Console/Cli/Unsafe/IUnsafeConfigurator.cs +++ b/src/Spectre.Console/Cli/Unsafe/IUnsafeConfigurator.cs @@ -1,26 +1,25 @@ using System; -namespace Spectre.Console.Cli.Unsafe +namespace Spectre.Console.Cli.Unsafe; + +/// +/// Represents an unsafe configurator. +/// +public interface IUnsafeConfigurator { /// - /// Represents an unsafe configurator. + /// Adds a command. /// - public interface IUnsafeConfigurator - { - /// - /// Adds a command. - /// - /// The name of the command. - /// The command type. - /// A command configurator that can be used to configure the command further. - ICommandConfigurator AddCommand(string name, Type command); + /// The name of the command. + /// The command type. + /// A command configurator that can be used to configure the command further. + ICommandConfigurator AddCommand(string name, Type command); - /// - /// Adds a command branch. - /// - /// The name of the command branch. - /// The command setting type. - /// The command branch configurator. - void AddBranch(string name, Type settings, Action action); - } -} + /// + /// Adds a command branch. + /// + /// The name of the command branch. + /// The command setting type. + /// The command branch configurator. + void AddBranch(string name, Type settings, Action action); +} \ No newline at end of file diff --git a/src/Spectre.Console/Cli/Unsafe/UnsafeConfiguratorExtensions.cs b/src/Spectre.Console/Cli/Unsafe/UnsafeConfiguratorExtensions.cs index 84e89a5..63d25eb 100644 --- a/src/Spectre.Console/Cli/Unsafe/UnsafeConfiguratorExtensions.cs +++ b/src/Spectre.Console/Cli/Unsafe/UnsafeConfiguratorExtensions.cs @@ -1,83 +1,82 @@ using System.Linq; -namespace Spectre.Console.Cli.Unsafe +namespace Spectre.Console.Cli.Unsafe; + +/// +/// Contains unsafe extensions for . +/// +public static class UnsafeConfiguratorExtensions { /// - /// Contains unsafe extensions for . + /// Gets an that allows + /// composition of commands without type safety. /// - public static class UnsafeConfiguratorExtensions + /// The configurator. + /// An . + public static IUnsafeConfigurator SafetyOff(this IConfigurator configurator) { - /// - /// Gets an that allows - /// composition of commands without type safety. - /// - /// The configurator. - /// An . - public static IUnsafeConfigurator SafetyOff(this IConfigurator configurator) + if (!(configurator is IUnsafeConfigurator @unsafe)) { - if (!(configurator is IUnsafeConfigurator @unsafe)) - { - throw new CommandConfigurationException("Configurator does not support manual configuration"); - } - - return @unsafe; + throw new CommandConfigurationException("Configurator does not support manual configuration"); } - /// - /// Converts an to - /// a configurator with type safety. - /// - /// The configurator. - /// An . - public static IConfigurator SafetyOn(this IUnsafeConfigurator configurator) - { - if (!(configurator is IConfigurator safe)) - { - throw new CommandConfigurationException("Configurator cannot be converted to a safe configurator."); - } - - return safe; - } - - /// - /// Gets an that allows - /// composition of commands without type safety. - /// - /// The command settings. - /// The configurator. - /// An . - public static IUnsafeConfigurator SafetyOff(this IConfigurator configurator) - where TSettings : CommandSettings - { - if (!(configurator is IUnsafeConfigurator @unsafe)) - { - throw new CommandConfigurationException("Configurator does not support manual configuration"); - } - - return @unsafe; - } - - /// - /// Converts an to - /// a configurator with type safety. - /// - /// The command settings. - /// The configurator. - /// An . - public static IConfigurator SafetyOn(this IUnsafeBranchConfigurator configurator) - where TSettings : CommandSettings - { - if (!(configurator is IConfigurator safe)) - { - throw new CommandConfigurationException($"Configurator cannot be converted to a safe configurator of type '{typeof(TSettings).Name}'."); - } - - if (safe.GetType().GetGenericArguments().First() != typeof(TSettings)) - { - throw new CommandConfigurationException($"Configurator cannot be converted to a safe configurator of type '{typeof(TSettings).Name}'."); - } - - return safe; - } + return @unsafe; } -} + + /// + /// Converts an to + /// a configurator with type safety. + /// + /// The configurator. + /// An . + public static IConfigurator SafetyOn(this IUnsafeConfigurator configurator) + { + if (!(configurator is IConfigurator safe)) + { + throw new CommandConfigurationException("Configurator cannot be converted to a safe configurator."); + } + + return safe; + } + + /// + /// Gets an that allows + /// composition of commands without type safety. + /// + /// The command settings. + /// The configurator. + /// An . + public static IUnsafeConfigurator SafetyOff(this IConfigurator configurator) + where TSettings : CommandSettings + { + if (!(configurator is IUnsafeConfigurator @unsafe)) + { + throw new CommandConfigurationException("Configurator does not support manual configuration"); + } + + return @unsafe; + } + + /// + /// Converts an to + /// a configurator with type safety. + /// + /// The command settings. + /// The configurator. + /// An . + public static IConfigurator SafetyOn(this IUnsafeBranchConfigurator configurator) + where TSettings : CommandSettings + { + if (!(configurator is IConfigurator safe)) + { + throw new CommandConfigurationException($"Configurator cannot be converted to a safe configurator of type '{typeof(TSettings).Name}'."); + } + + if (safe.GetType().GetGenericArguments().First() != typeof(TSettings)) + { + throw new CommandConfigurationException($"Configurator cannot be converted to a safe configurator of type '{typeof(TSettings).Name}'."); + } + + return safe; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Color.cs b/src/Spectre.Console/Color.cs index 36e51cb..91ebf62 100644 --- a/src/Spectre.Console/Color.cs +++ b/src/Spectre.Console/Color.cs @@ -2,291 +2,290 @@ using System; using System.Diagnostics; using System.Globalization; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Represents a color. +/// +public partial struct Color : IEquatable { /// - /// Represents a color. + /// Gets the default color. /// - public partial struct Color : IEquatable + public static Color Default { get; } + + static Color() { - /// - /// Gets the default color. - /// - public static Color Default { get; } + Default = new Color(0, 0, 0, 0, true); + } - static Color() + /// + /// Gets the red component. + /// + public byte R { get; } + + /// + /// Gets the green component. + /// + public byte G { get; } + + /// + /// Gets the blue component. + /// + public byte B { get; } + + /// + /// Gets the number of the color, if any. + /// + internal byte? Number { get; } + + /// + /// Gets a value indicating whether or not this is the default color. + /// + internal bool IsDefault { get; } + + /// + /// Initializes a new instance of the struct. + /// + /// The red component. + /// The green component. + /// The blue component. + public Color(byte red, byte green, byte blue) + { + R = red; + G = green; + B = blue; + IsDefault = false; + Number = null; + } + + /// + /// Blends two colors. + /// + /// The other color. + /// The blend factor. + /// The resulting color. + public Color Blend(Color other, float factor) + { + // https://github.com/willmcgugan/rich/blob/f092b1d04252e6f6812021c0f415dd1d7be6a16a/rich/color.py#L494 + return new Color( + (byte)(R + ((other.R - R) * factor)), + (byte)(G + ((other.G - G) * factor)), + (byte)(B + ((other.B - B) * factor))); + } + + /// + /// Gets the hexadecimal representation of the color. + /// + /// The hexadecimal representation of the color. + public string ToHex() + { + return string.Format( + CultureInfo.InvariantCulture, + "{0}{1}{2}", + R.ToString("X2", CultureInfo.InvariantCulture), + G.ToString("X2", CultureInfo.InvariantCulture), + B.ToString("X2", CultureInfo.InvariantCulture)); + } + + /// + public override int GetHashCode() + { + unchecked { - Default = new Color(0, 0, 0, 0, true); - } - - /// - /// Gets the red component. - /// - public byte R { get; } - - /// - /// Gets the green component. - /// - public byte G { get; } - - /// - /// Gets the blue component. - /// - public byte B { get; } - - /// - /// Gets the number of the color, if any. - /// - internal byte? Number { get; } - - /// - /// Gets a value indicating whether or not this is the default color. - /// - internal bool IsDefault { get; } - - /// - /// Initializes a new instance of the struct. - /// - /// The red component. - /// The green component. - /// The blue component. - public Color(byte red, byte green, byte blue) - { - R = red; - G = green; - B = blue; - IsDefault = false; - Number = null; - } - - /// - /// Blends two colors. - /// - /// The other color. - /// The blend factor. - /// The resulting color. - public Color Blend(Color other, float factor) - { - // https://github.com/willmcgugan/rich/blob/f092b1d04252e6f6812021c0f415dd1d7be6a16a/rich/color.py#L494 - return new Color( - (byte)(R + ((other.R - R) * factor)), - (byte)(G + ((other.G - G) * factor)), - (byte)(B + ((other.B - B) * factor))); - } - - /// - /// Gets the hexadecimal representation of the color. - /// - /// The hexadecimal representation of the color. - public string ToHex() - { - return string.Format( - CultureInfo.InvariantCulture, - "{0}{1}{2}", - R.ToString("X2", CultureInfo.InvariantCulture), - G.ToString("X2", CultureInfo.InvariantCulture), - B.ToString("X2", CultureInfo.InvariantCulture)); - } - - /// - public override int GetHashCode() - { - unchecked - { - var hash = (int)2166136261; - hash = (hash * 16777619) ^ R.GetHashCode(); - hash = (hash * 16777619) ^ G.GetHashCode(); - hash = (hash * 16777619) ^ B.GetHashCode(); - return hash; - } - } - - /// - public override bool Equals(object? obj) - { - return obj is Color color && Equals(color); - } - - /// - public bool Equals(Color other) - { - return (IsDefault && other.IsDefault) || - (IsDefault == other.IsDefault && R == other.R && G == other.G && B == other.B); - } - - /// - /// Checks if two instances are equal. - /// - /// The first color instance to compare. - /// The second color instance to compare. - /// true if the two colors are equal, otherwise false. - public static bool operator ==(Color left, Color right) - { - return left.Equals(right); - } - - /// - /// Checks if two instances are not equal. - /// - /// The first color instance to compare. - /// The second color instance to compare. - /// true if the two colors are not equal, otherwise false. - public static bool operator !=(Color left, Color right) - { - return !(left == right); - } - - /// - /// Converts a to a . - /// - /// The color number to convert. - public static implicit operator Color(int number) - { - return FromInt32(number); - } - - /// - /// Converts a to a . - /// - /// The color to convert. - public static implicit operator Color(ConsoleColor color) - { - return FromConsoleColor(color); - } - - /// - /// Converts a to a . - /// - /// The console color to convert. - public static implicit operator ConsoleColor(Color color) - { - return ToConsoleColor(color); - } - - /// - /// Converts a to a . - /// - /// The color to convert. - /// A representing the . - public static ConsoleColor ToConsoleColor(Color color) - { - if (color.IsDefault) - { - return (ConsoleColor)(-1); - } - - if (color.Number == null || color.Number.Value >= 16) - { - color = ColorPalette.ExactOrClosest(ColorSystem.Standard, color); - } - - // Should not happen, but this will make things easier if we mess things up... - Debug.Assert( - color.Number >= 0 && color.Number < 16, - "Color does not fall inside the standard palette range."); - - return color.Number.Value switch - { - 0 => ConsoleColor.Black, - 1 => ConsoleColor.DarkRed, - 2 => ConsoleColor.DarkGreen, - 3 => ConsoleColor.DarkYellow, - 4 => ConsoleColor.DarkBlue, - 5 => ConsoleColor.DarkMagenta, - 6 => ConsoleColor.DarkCyan, - 7 => ConsoleColor.Gray, - 8 => ConsoleColor.DarkGray, - 9 => ConsoleColor.Red, - 10 => ConsoleColor.Green, - 11 => ConsoleColor.Yellow, - 12 => ConsoleColor.Blue, - 13 => ConsoleColor.Magenta, - 14 => ConsoleColor.Cyan, - 15 => ConsoleColor.White, - _ => throw new InvalidOperationException("Cannot convert color to console color."), - }; - } - - /// - /// Converts a color number into a . - /// - /// The color number. - /// The color representing the specified color number. - public static Color FromInt32(int number) - { - return ColorTable.GetColor(number); - } - - /// - /// Converts a to a . - /// - /// The color to convert. - /// A representing the . - public static Color FromConsoleColor(ConsoleColor color) - { - return color switch - { - ConsoleColor.Black => Black, - ConsoleColor.Blue => Blue, - ConsoleColor.Cyan => Aqua, - ConsoleColor.DarkBlue => Navy, - ConsoleColor.DarkCyan => Teal, - ConsoleColor.DarkGray => Grey, - ConsoleColor.DarkGreen => Green, - ConsoleColor.DarkMagenta => Purple, - ConsoleColor.DarkRed => Maroon, - ConsoleColor.DarkYellow => Olive, - ConsoleColor.Gray => Silver, - ConsoleColor.Green => Lime, - ConsoleColor.Magenta => Fuchsia, - ConsoleColor.Red => Red, - ConsoleColor.White => White, - ConsoleColor.Yellow => Yellow, - _ => Default, - }; - } - - /// - /// Converts the color to a markup string. - /// - /// A representing the color as markup. - public string ToMarkup() - { - if (IsDefault) - { - return "default"; - } - - if (Number != null) - { - var name = ColorTable.GetName(Number.Value); - if (!string.IsNullOrWhiteSpace(name)) - { - return name; - } - } - - return string.Format(CultureInfo.InvariantCulture, "#{0:X2}{1:X2}{2:X2}", R, G, B); - } - - /// - public override string ToString() - { - if (IsDefault) - { - return "default"; - } - - if (Number != null) - { - var name = ColorTable.GetName(Number.Value); - if (!string.IsNullOrWhiteSpace(name)) - { - return name; - } - } - - return string.Format(CultureInfo.InvariantCulture, "#{0:X2}{1:X2}{2:X2} (RGB={0},{1},{2})", R, G, B); + var hash = (int)2166136261; + hash = (hash * 16777619) ^ R.GetHashCode(); + hash = (hash * 16777619) ^ G.GetHashCode(); + hash = (hash * 16777619) ^ B.GetHashCode(); + return hash; } } -} + + /// + public override bool Equals(object? obj) + { + return obj is Color color && Equals(color); + } + + /// + public bool Equals(Color other) + { + return (IsDefault && other.IsDefault) || + (IsDefault == other.IsDefault && R == other.R && G == other.G && B == other.B); + } + + /// + /// Checks if two instances are equal. + /// + /// The first color instance to compare. + /// The second color instance to compare. + /// true if the two colors are equal, otherwise false. + public static bool operator ==(Color left, Color right) + { + return left.Equals(right); + } + + /// + /// Checks if two instances are not equal. + /// + /// The first color instance to compare. + /// The second color instance to compare. + /// true if the two colors are not equal, otherwise false. + public static bool operator !=(Color left, Color right) + { + return !(left == right); + } + + /// + /// Converts a to a . + /// + /// The color number to convert. + public static implicit operator Color(int number) + { + return FromInt32(number); + } + + /// + /// Converts a to a . + /// + /// The color to convert. + public static implicit operator Color(ConsoleColor color) + { + return FromConsoleColor(color); + } + + /// + /// Converts a to a . + /// + /// The console color to convert. + public static implicit operator ConsoleColor(Color color) + { + return ToConsoleColor(color); + } + + /// + /// Converts a to a . + /// + /// The color to convert. + /// A representing the . + public static ConsoleColor ToConsoleColor(Color color) + { + if (color.IsDefault) + { + return (ConsoleColor)(-1); + } + + if (color.Number == null || color.Number.Value >= 16) + { + color = ColorPalette.ExactOrClosest(ColorSystem.Standard, color); + } + + // Should not happen, but this will make things easier if we mess things up... + Debug.Assert( + color.Number >= 0 && color.Number < 16, + "Color does not fall inside the standard palette range."); + + return color.Number.Value switch + { + 0 => ConsoleColor.Black, + 1 => ConsoleColor.DarkRed, + 2 => ConsoleColor.DarkGreen, + 3 => ConsoleColor.DarkYellow, + 4 => ConsoleColor.DarkBlue, + 5 => ConsoleColor.DarkMagenta, + 6 => ConsoleColor.DarkCyan, + 7 => ConsoleColor.Gray, + 8 => ConsoleColor.DarkGray, + 9 => ConsoleColor.Red, + 10 => ConsoleColor.Green, + 11 => ConsoleColor.Yellow, + 12 => ConsoleColor.Blue, + 13 => ConsoleColor.Magenta, + 14 => ConsoleColor.Cyan, + 15 => ConsoleColor.White, + _ => throw new InvalidOperationException("Cannot convert color to console color."), + }; + } + + /// + /// Converts a color number into a . + /// + /// The color number. + /// The color representing the specified color number. + public static Color FromInt32(int number) + { + return ColorTable.GetColor(number); + } + + /// + /// Converts a to a . + /// + /// The color to convert. + /// A representing the . + public static Color FromConsoleColor(ConsoleColor color) + { + return color switch + { + ConsoleColor.Black => Black, + ConsoleColor.Blue => Blue, + ConsoleColor.Cyan => Aqua, + ConsoleColor.DarkBlue => Navy, + ConsoleColor.DarkCyan => Teal, + ConsoleColor.DarkGray => Grey, + ConsoleColor.DarkGreen => Green, + ConsoleColor.DarkMagenta => Purple, + ConsoleColor.DarkRed => Maroon, + ConsoleColor.DarkYellow => Olive, + ConsoleColor.Gray => Silver, + ConsoleColor.Green => Lime, + ConsoleColor.Magenta => Fuchsia, + ConsoleColor.Red => Red, + ConsoleColor.White => White, + ConsoleColor.Yellow => Yellow, + _ => Default, + }; + } + + /// + /// Converts the color to a markup string. + /// + /// A representing the color as markup. + public string ToMarkup() + { + if (IsDefault) + { + return "default"; + } + + if (Number != null) + { + var name = ColorTable.GetName(Number.Value); + if (!string.IsNullOrWhiteSpace(name)) + { + return name; + } + } + + return string.Format(CultureInfo.InvariantCulture, "#{0:X2}{1:X2}{2:X2}", R, G, B); + } + + /// + public override string ToString() + { + if (IsDefault) + { + return "default"; + } + + if (Number != null) + { + var name = ColorTable.GetName(Number.Value); + if (!string.IsNullOrWhiteSpace(name)) + { + return name; + } + } + + return string.Format(CultureInfo.InvariantCulture, "#{0:X2}{1:X2}{2:X2} (RGB={0},{1},{2})", R, G, B); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/ColorSystem.cs b/src/Spectre.Console/ColorSystem.cs index f0e301d..29b940a 100644 --- a/src/Spectre.Console/ColorSystem.cs +++ b/src/Spectre.Console/ColorSystem.cs @@ -1,33 +1,32 @@ -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Represents a color system. +/// +public enum ColorSystem { /// - /// Represents a color system. + /// No colors. /// - public enum ColorSystem - { - /// - /// No colors. - /// - NoColors = 0, + NoColors = 0, - /// - /// Legacy, 3-bit mode. - /// - Legacy = 1, + /// + /// Legacy, 3-bit mode. + /// + Legacy = 1, - /// - /// Standard, 4-bit mode. - /// - Standard = 2, + /// + /// Standard, 4-bit mode. + /// + Standard = 2, - /// - /// 8-bit mode. - /// - EightBit = 3, + /// + /// 8-bit mode. + /// + EightBit = 3, - /// - /// 24-bit mode. - /// - TrueColor = 4, - } -} + /// + /// 24-bit mode. + /// + TrueColor = 4, +} \ No newline at end of file diff --git a/src/Spectre.Console/ColorSystemSupport.cs b/src/Spectre.Console/ColorSystemSupport.cs index cdff656..91dc244 100644 --- a/src/Spectre.Console/ColorSystemSupport.cs +++ b/src/Spectre.Console/ColorSystemSupport.cs @@ -1,38 +1,37 @@ -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Determines what color system should be used. +/// +public enum ColorSystemSupport { /// - /// Determines what color system should be used. + /// Try to detect the color system. /// - public enum ColorSystemSupport - { - /// - /// Try to detect the color system. - /// - Detect = -1, + Detect = -1, - /// - /// No colors. - /// - NoColors = 0, + /// + /// No colors. + /// + NoColors = 0, - /// - /// Legacy, 3-bit mode. - /// - Legacy = 1, + /// + /// Legacy, 3-bit mode. + /// + Legacy = 1, - /// - /// Standard, 4-bit mode. - /// - Standard = 2, + /// + /// Standard, 4-bit mode. + /// + Standard = 2, - /// - /// 8-bit mode. - /// - EightBit = 3, + /// + /// 8-bit mode. + /// + EightBit = 3, - /// - /// 24-bit mode. - /// - TrueColor = 4, - } -} + /// + /// 24-bit mode. + /// + TrueColor = 4, +} \ No newline at end of file diff --git a/src/Spectre.Console/CursorDirection.cs b/src/Spectre.Console/CursorDirection.cs index 3ce1f5e..06bff42 100644 --- a/src/Spectre.Console/CursorDirection.cs +++ b/src/Spectre.Console/CursorDirection.cs @@ -1,28 +1,27 @@ -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Represents cursor direction. +/// +public enum CursorDirection { /// - /// Represents cursor direction. + /// Moves cursor up. /// - public enum CursorDirection - { - /// - /// Moves cursor up. - /// - Up, + Up, - /// - /// Moves cursor down. - /// - Down, + /// + /// Moves cursor down. + /// + Down, - /// - /// Moves cursor left. - /// - Left, + /// + /// Moves cursor left. + /// + Left, - /// - /// Moves cursor right. - /// - Right, - } -} + /// + /// Moves cursor right. + /// + Right, +} \ No newline at end of file diff --git a/src/Spectre.Console/Decoration.cs b/src/Spectre.Console/Decoration.cs index c759a58..219374b 100644 --- a/src/Spectre.Console/Decoration.cs +++ b/src/Spectre.Console/Decoration.cs @@ -1,75 +1,74 @@ using System; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Represents text decoration. +/// +/// +/// Support for text decorations is up to the terminal. +/// +[Flags] +public enum Decoration { /// - /// Represents text decoration. + /// No text decoration. /// - /// - /// Support for text decorations is up to the terminal. - /// - [Flags] - public enum Decoration - { - /// - /// No text decoration. - /// - None = 0, + None = 0, - /// - /// Bold text. - /// Not supported in every environment. - /// - Bold = 1 << 0, + /// + /// Bold text. + /// Not supported in every environment. + /// + Bold = 1 << 0, - /// - /// Dim or faint text. - /// Not supported in every environment. - /// - Dim = 1 << 1, + /// + /// Dim or faint text. + /// Not supported in every environment. + /// + Dim = 1 << 1, - /// - /// Italic text. - /// Not supported in every environment. - /// - Italic = 1 << 2, + /// + /// Italic text. + /// Not supported in every environment. + /// + Italic = 1 << 2, - /// - /// Underlined text. - /// Not supported in every environment. - /// - Underline = 1 << 3, + /// + /// Underlined text. + /// Not supported in every environment. + /// + Underline = 1 << 3, - /// - /// Swaps the foreground and background colors. - /// Not supported in every environment. - /// - Invert = 1 << 4, + /// + /// Swaps the foreground and background colors. + /// Not supported in every environment. + /// + Invert = 1 << 4, - /// - /// Hides the text. - /// Not supported in every environment. - /// - Conceal = 1 << 5, + /// + /// Hides the text. + /// Not supported in every environment. + /// + Conceal = 1 << 5, - /// - /// Makes text blink. - /// Normally less than 150 blinks per minute. - /// Not supported in every environment. - /// - SlowBlink = 1 << 6, + /// + /// Makes text blink. + /// Normally less than 150 blinks per minute. + /// Not supported in every environment. + /// + SlowBlink = 1 << 6, - /// - /// Makes text blink. - /// Normally more than 150 blinks per minute. - /// Not supported in every environment. - /// - RapidBlink = 1 << 7, + /// + /// Makes text blink. + /// Normally more than 150 blinks per minute. + /// Not supported in every environment. + /// + RapidBlink = 1 << 7, - /// - /// Shows text with a horizontal line through the center. - /// Not supported in every environment. - /// - Strikethrough = 1 << 8, - } -} + /// + /// Shows text with a horizontal line through the center. + /// Not supported in every environment. + /// + Strikethrough = 1 << 8, +} \ No newline at end of file diff --git a/src/Spectre.Console/Emoji.cs b/src/Spectre.Console/Emoji.cs index 89afcc6..465ed38 100644 --- a/src/Spectre.Console/Emoji.cs +++ b/src/Spectre.Console/Emoji.cs @@ -2,131 +2,130 @@ using System; using System.Collections.Generic; using System.Text; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Utility for working with emojis. +/// +public static partial class Emoji { - /// - /// Utility for working with emojis. - /// - public static partial class Emoji + private static readonly Dictionary _remappings; + + static Emoji() { - private static readonly Dictionary _remappings; + _remappings = new Dictionary(StringComparer.OrdinalIgnoreCase); + } - static Emoji() + /// + /// Remaps a specific emoji tag with a new emoji. + /// + /// The emoji tag. + /// The emoji. + public static void Remap(string tag, string emoji) + { + if (tag is null) { - _remappings = new Dictionary(StringComparer.OrdinalIgnoreCase); + throw new ArgumentNullException(nameof(tag)); } - /// - /// Remaps a specific emoji tag with a new emoji. - /// - /// The emoji tag. - /// The emoji. - public static void Remap(string tag, string emoji) + if (emoji is null) { - if (tag is null) - { - throw new ArgumentNullException(nameof(tag)); - } - - if (emoji is null) - { - throw new ArgumentNullException(nameof(emoji)); - } - - tag = tag.TrimStart(':').TrimEnd(':'); - emoji = emoji.TrimStart(':').TrimEnd(':'); - - _remappings[tag] = emoji; + throw new ArgumentNullException(nameof(emoji)); } + tag = tag.TrimStart(':').TrimEnd(':'); + emoji = emoji.TrimStart(':').TrimEnd(':'); + + _remappings[tag] = emoji; + } + #if NETSTANDARD2_0 - /// - /// Replaces emoji markup with corresponding unicode characters. - /// - /// A string with emojis codes, e.g. "Hello :smiley:!". - /// A string with emoji codes replaced with actual emoji. - public static string Replace(string value) - { - return Replace(value.AsSpan()); - } + /// + /// Replaces emoji markup with corresponding unicode characters. + /// + /// A string with emojis codes, e.g. "Hello :smiley:!". + /// A string with emoji codes replaced with actual emoji. + public static string Replace(string value) + { + return Replace(value.AsSpan()); + } #endif - /// - /// Replaces emoji markup with corresponding unicode characters. - /// - /// A string with emojis codes, e.g. "Hello :smiley:!". - /// A string with emoji codes replaced with actual emoji. - public static string Replace(ReadOnlySpan value) + /// + /// Replaces emoji markup with corresponding unicode characters. + /// + /// A string with emojis codes, e.g. "Hello :smiley:!". + /// A string with emoji codes replaced with actual emoji. + public static string Replace(ReadOnlySpan value) + { + var output = new StringBuilder(); + var colonPos = value.IndexOf(':'); + if (colonPos == -1) { - var output = new StringBuilder(); - var colonPos = value.IndexOf(':'); - if (colonPos == -1) - { - // No colons, no emoji. return what was passed in with no changes. - return value.ToString(); - } - - while ((colonPos = value.IndexOf(':')) != -1) - { - // Append text up to colon - output.AppendSpan(value.Slice(0, colonPos)); - - // Set value equal to that colon and the rest of the string - value = value.Slice(colonPos); - - // Find colon after that. if no colon, break out - var nextColonPos = value.IndexOf(':', 1); - if (nextColonPos == -1) - { - break; - } - - // Get the emoji text minus the colons - var emojiKey = value.Slice(1, nextColonPos - 1).ToString(); - if (TryGetEmoji(emojiKey, out var emojiValue)) - { - output.Append(emojiValue); - value = value.Slice(nextColonPos + 1); - } - else - { - output.Append(':'); - value = value.Slice(1); - } - } - - output.AppendSpan(value); - return output.ToString(); + // No colons, no emoji. return what was passed in with no changes. + return value.ToString(); } - private static bool TryGetEmoji(string emoji, out string value) + while ((colonPos = value.IndexOf(':')) != -1) { - if (_remappings.TryGetValue(emoji, out var remappedEmojiValue)) + // Append text up to colon + output.AppendSpan(value.Slice(0, colonPos)); + + // Set value equal to that colon and the rest of the string + value = value.Slice(colonPos); + + // Find colon after that. if no colon, break out + var nextColonPos = value.IndexOf(':', 1); + if (nextColonPos == -1) { - value = remappedEmojiValue; - return true; + break; } - if (_emojis.TryGetValue(emoji, out var emojiValue)) + // Get the emoji text minus the colons + var emojiKey = value.Slice(1, nextColonPos - 1).ToString(); + if (TryGetEmoji(emojiKey, out var emojiValue)) { - value = emojiValue; - return true; + output.Append(emojiValue); + value = value.Slice(nextColonPos + 1); + } + else + { + output.Append(':'); + value = value.Slice(1); } - - value = string.Empty; - return false; } - private static int IndexOf(this ReadOnlySpan span, char value, int startIndex) + output.AppendSpan(value); + return output.ToString(); + } + + private static bool TryGetEmoji(string emoji, out string value) + { + if (_remappings.TryGetValue(emoji, out var remappedEmojiValue)) { - var indexInSlice = span.Slice(startIndex).IndexOf(value); - - if (indexInSlice == -1) - { - return -1; - } - - return startIndex + indexInSlice; + value = remappedEmojiValue; + return true; } + + if (_emojis.TryGetValue(emoji, out var emojiValue)) + { + value = emojiValue; + return true; + } + + value = string.Empty; + return false; + } + + private static int IndexOf(this ReadOnlySpan span, char value, int startIndex) + { + var indexInSlice = span.Slice(startIndex).IndexOf(value); + + if (indexInSlice == -1) + { + return -1; + } + + return startIndex + indexInSlice; } } \ No newline at end of file diff --git a/src/Spectre.Console/Enrichment/CI/AppVeyorEnricher.cs b/src/Spectre.Console/Enrichment/CI/AppVeyorEnricher.cs index a7cb5c2..c1c710d 100644 --- a/src/Spectre.Console/Enrichment/CI/AppVeyorEnricher.cs +++ b/src/Spectre.Console/Enrichment/CI/AppVeyorEnricher.cs @@ -1,19 +1,18 @@ using System.Collections.Generic; -namespace Spectre.Console.Enrichment +namespace Spectre.Console.Enrichment; + +internal sealed class AppVeyorEnricher : IProfileEnricher { - internal sealed class AppVeyorEnricher : IProfileEnricher + public string Name => "AppVeyor"; + + public bool Enabled(IDictionary environmentVariables) { - public string Name => "AppVeyor"; - - public bool Enabled(IDictionary environmentVariables) - { - return environmentVariables.ContainsKey("APPVEYOR"); - } - - public void Enrich(Profile profile) - { - profile.Capabilities.Interactive = false; - } + return environmentVariables.ContainsKey("APPVEYOR"); } -} + + public void Enrich(Profile profile) + { + profile.Capabilities.Interactive = false; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Enrichment/CI/BambooEnricher.cs b/src/Spectre.Console/Enrichment/CI/BambooEnricher.cs index 6a3520e..db135a5 100644 --- a/src/Spectre.Console/Enrichment/CI/BambooEnricher.cs +++ b/src/Spectre.Console/Enrichment/CI/BambooEnricher.cs @@ -1,19 +1,18 @@ using System.Collections.Generic; -namespace Spectre.Console.Enrichment +namespace Spectre.Console.Enrichment; + +internal sealed class BambooEnricher : IProfileEnricher { - internal sealed class BambooEnricher : IProfileEnricher + public string Name => "Bamboo"; + + public bool Enabled(IDictionary environmentVariables) { - public string Name => "Bamboo"; - - public bool Enabled(IDictionary environmentVariables) - { - return environmentVariables.ContainsKey("bamboo_buildNumber"); - } - - public void Enrich(Profile profile) - { - profile.Capabilities.Interactive = false; - } + return environmentVariables.ContainsKey("bamboo_buildNumber"); } -} + + public void Enrich(Profile profile) + { + profile.Capabilities.Interactive = false; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Enrichment/CI/BitbucketEnricher.cs b/src/Spectre.Console/Enrichment/CI/BitbucketEnricher.cs index 2237ea3..e990111 100644 --- a/src/Spectre.Console/Enrichment/CI/BitbucketEnricher.cs +++ b/src/Spectre.Console/Enrichment/CI/BitbucketEnricher.cs @@ -1,21 +1,20 @@ using System.Collections.Generic; -namespace Spectre.Console.Enrichment +namespace Spectre.Console.Enrichment; + +internal sealed class BitbucketEnricher : IProfileEnricher { - internal sealed class BitbucketEnricher : IProfileEnricher + public string Name => "Bitbucket"; + + public bool Enabled(IDictionary environmentVariables) { - public string Name => "Bitbucket"; - - public bool Enabled(IDictionary environmentVariables) - { - return environmentVariables.ContainsKey("BITBUCKET_REPO_OWNER") || - environmentVariables.ContainsKey("BITBUCKET_REPO_SLUG") || - environmentVariables.ContainsKey("BITBUCKET_COMMIT"); - } - - public void Enrich(Profile profile) - { - profile.Capabilities.Interactive = false; - } + return environmentVariables.ContainsKey("BITBUCKET_REPO_OWNER") || + environmentVariables.ContainsKey("BITBUCKET_REPO_SLUG") || + environmentVariables.ContainsKey("BITBUCKET_COMMIT"); } -} + + public void Enrich(Profile profile) + { + profile.Capabilities.Interactive = false; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Enrichment/CI/BitriseEnricher.cs b/src/Spectre.Console/Enrichment/CI/BitriseEnricher.cs index a3d0fc1..515f471 100644 --- a/src/Spectre.Console/Enrichment/CI/BitriseEnricher.cs +++ b/src/Spectre.Console/Enrichment/CI/BitriseEnricher.cs @@ -1,19 +1,18 @@ using System.Collections.Generic; -namespace Spectre.Console.Enrichment +namespace Spectre.Console.Enrichment; + +internal sealed class BitriseEnricher : IProfileEnricher { - internal sealed class BitriseEnricher : IProfileEnricher + public string Name => "Bitrise"; + + public bool Enabled(IDictionary environmentVariables) { - public string Name => "Bitrise"; - - public bool Enabled(IDictionary environmentVariables) - { - return environmentVariables.ContainsKey("BITRISE_BUILD_URL"); - } - - public void Enrich(Profile profile) - { - profile.Capabilities.Interactive = false; - } + return environmentVariables.ContainsKey("BITRISE_BUILD_URL"); } -} + + public void Enrich(Profile profile) + { + profile.Capabilities.Interactive = false; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Enrichment/CI/ContinuaEnricher.cs b/src/Spectre.Console/Enrichment/CI/ContinuaEnricher.cs index e1b70e2..59eb240 100644 --- a/src/Spectre.Console/Enrichment/CI/ContinuaEnricher.cs +++ b/src/Spectre.Console/Enrichment/CI/ContinuaEnricher.cs @@ -1,19 +1,18 @@ using System.Collections.Generic; -namespace Spectre.Console.Enrichment +namespace Spectre.Console.Enrichment; + +internal sealed class ContinuaEnricher : IProfileEnricher { - internal sealed class ContinuaEnricher : IProfileEnricher + public string Name => "ContinuaCI"; + + public bool Enabled(IDictionary environmentVariables) { - public string Name => "ContinuaCI"; - - public bool Enabled(IDictionary environmentVariables) - { - return environmentVariables.ContainsKey("ContinuaCI.Version"); - } - - public void Enrich(Profile profile) - { - profile.Capabilities.Interactive = false; - } + return environmentVariables.ContainsKey("ContinuaCI.Version"); } -} + + public void Enrich(Profile profile) + { + profile.Capabilities.Interactive = false; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Enrichment/CI/GitHubEnricher.cs b/src/Spectre.Console/Enrichment/CI/GitHubEnricher.cs index 5d18f47..c8ce699 100644 --- a/src/Spectre.Console/Enrichment/CI/GitHubEnricher.cs +++ b/src/Spectre.Console/Enrichment/CI/GitHubEnricher.cs @@ -1,28 +1,27 @@ using System; using System.Collections.Generic; -namespace Spectre.Console.Enrichment +namespace Spectre.Console.Enrichment; + +internal sealed class GitHubEnricher : IProfileEnricher { - internal sealed class GitHubEnricher : IProfileEnricher + public string Name => "GitHub"; + + public bool Enabled(IDictionary environmentVariables) { - public string Name => "GitHub"; - - public bool Enabled(IDictionary environmentVariables) + if (environmentVariables.TryGetValue("GITHUB_ACTIONS", out var value)) { - if (environmentVariables.TryGetValue("GITHUB_ACTIONS", out var value)) - { - return value?.Equals("true", StringComparison.OrdinalIgnoreCase) ?? false; - } - - return false; + return value?.Equals("true", StringComparison.OrdinalIgnoreCase) ?? false; } - public void Enrich(Profile profile) - { - profile.Capabilities.Ansi = true; - profile.Capabilities.Legacy = false; - profile.Capabilities.Interactive = false; - profile.Capabilities.Links = false; - } + return false; } -} + + public void Enrich(Profile profile) + { + profile.Capabilities.Ansi = true; + profile.Capabilities.Legacy = false; + profile.Capabilities.Interactive = false; + profile.Capabilities.Links = false; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Enrichment/CI/GitLabEnricher.cs b/src/Spectre.Console/Enrichment/CI/GitLabEnricher.cs index 7e170c6..e668f3d 100644 --- a/src/Spectre.Console/Enrichment/CI/GitLabEnricher.cs +++ b/src/Spectre.Console/Enrichment/CI/GitLabEnricher.cs @@ -1,25 +1,24 @@ using System; using System.Collections.Generic; -namespace Spectre.Console.Enrichment +namespace Spectre.Console.Enrichment; + +internal sealed class GitLabEnricher : IProfileEnricher { - internal sealed class GitLabEnricher : IProfileEnricher + public string Name => "GitLab"; + + public bool Enabled(IDictionary environmentVariables) { - public string Name => "GitLab"; - - public bool Enabled(IDictionary environmentVariables) + if (environmentVariables.TryGetValue("CI_SERVER", out var value)) { - if (environmentVariables.TryGetValue("CI_SERVER", out var value)) - { - return value?.Equals("yes", StringComparison.OrdinalIgnoreCase) ?? false; - } - - return false; + return value?.Equals("yes", StringComparison.OrdinalIgnoreCase) ?? false; } - public void Enrich(Profile profile) - { - profile.Capabilities.Interactive = false; - } + return false; } -} + + public void Enrich(Profile profile) + { + profile.Capabilities.Interactive = false; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Enrichment/CI/GoCDEnricher.cs b/src/Spectre.Console/Enrichment/CI/GoCDEnricher.cs index 769d865..9baa6bb 100644 --- a/src/Spectre.Console/Enrichment/CI/GoCDEnricher.cs +++ b/src/Spectre.Console/Enrichment/CI/GoCDEnricher.cs @@ -1,19 +1,18 @@ using System.Collections.Generic; -namespace Spectre.Console.Enrichment +namespace Spectre.Console.Enrichment; + +internal sealed class GoCDEnricher : IProfileEnricher { - internal sealed class GoCDEnricher : IProfileEnricher + public string Name => "GoCD"; + + public bool Enabled(IDictionary environmentVariables) { - public string Name => "GoCD"; - - public bool Enabled(IDictionary environmentVariables) - { - return environmentVariables.ContainsKey("GO_SERVER_URL"); - } - - public void Enrich(Profile profile) - { - profile.Capabilities.Interactive = false; - } + return environmentVariables.ContainsKey("GO_SERVER_URL"); } -} + + public void Enrich(Profile profile) + { + profile.Capabilities.Interactive = false; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Enrichment/CI/JenkinsEnricher.cs b/src/Spectre.Console/Enrichment/CI/JenkinsEnricher.cs index aebf806..ff2e30d 100644 --- a/src/Spectre.Console/Enrichment/CI/JenkinsEnricher.cs +++ b/src/Spectre.Console/Enrichment/CI/JenkinsEnricher.cs @@ -1,19 +1,18 @@ using System.Collections.Generic; -namespace Spectre.Console.Enrichment +namespace Spectre.Console.Enrichment; + +internal sealed class JenkinsEnricher : IProfileEnricher { - internal sealed class JenkinsEnricher : IProfileEnricher + public string Name => "Jenkins"; + + public bool Enabled(IDictionary environmentVariables) { - public string Name => "Jenkins"; - - public bool Enabled(IDictionary environmentVariables) - { - return environmentVariables.ContainsKey("JENKINS_URL"); - } - - public void Enrich(Profile profile) - { - profile.Capabilities.Interactive = false; - } + return environmentVariables.ContainsKey("JENKINS_URL"); } -} + + public void Enrich(Profile profile) + { + profile.Capabilities.Interactive = false; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Enrichment/CI/MyGetEnricher.cs b/src/Spectre.Console/Enrichment/CI/MyGetEnricher.cs index d33198b..4eb2424 100644 --- a/src/Spectre.Console/Enrichment/CI/MyGetEnricher.cs +++ b/src/Spectre.Console/Enrichment/CI/MyGetEnricher.cs @@ -1,25 +1,24 @@ using System; using System.Collections.Generic; -namespace Spectre.Console.Enrichment +namespace Spectre.Console.Enrichment; + +internal sealed class MyGetEnricher : IProfileEnricher { - internal sealed class MyGetEnricher : IProfileEnricher + public string Name => "MyGet"; + + public bool Enabled(IDictionary environmentVariables) { - public string Name => "MyGet"; - - public bool Enabled(IDictionary environmentVariables) + if (environmentVariables.TryGetValue("BuildRunner", out var value)) { - if (environmentVariables.TryGetValue("BuildRunner", out var value)) - { - return value?.Equals("MyGet", StringComparison.OrdinalIgnoreCase) ?? false; - } - - return false; + return value?.Equals("MyGet", StringComparison.OrdinalIgnoreCase) ?? false; } - public void Enrich(Profile profile) - { - profile.Capabilities.Interactive = false; - } + return false; } -} + + public void Enrich(Profile profile) + { + profile.Capabilities.Interactive = false; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Enrichment/CI/TeamCityEnricher.cs b/src/Spectre.Console/Enrichment/CI/TeamCityEnricher.cs index fc4b730..ae8fb30 100644 --- a/src/Spectre.Console/Enrichment/CI/TeamCityEnricher.cs +++ b/src/Spectre.Console/Enrichment/CI/TeamCityEnricher.cs @@ -1,19 +1,18 @@ using System.Collections.Generic; -namespace Spectre.Console.Enrichment +namespace Spectre.Console.Enrichment; + +internal sealed class TeamCityEnricher : IProfileEnricher { - internal sealed class TeamCityEnricher : IProfileEnricher + public string Name => "TeamCity"; + + public bool Enabled(IDictionary environmentVariables) { - public string Name => "TeamCity"; - - public bool Enabled(IDictionary environmentVariables) - { - return environmentVariables.ContainsKey("TEAMCITY_VERSION"); - } - - public void Enrich(Profile profile) - { - profile.Capabilities.Interactive = false; - } + return environmentVariables.ContainsKey("TEAMCITY_VERSION"); } -} + + public void Enrich(Profile profile) + { + profile.Capabilities.Interactive = false; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Enrichment/CI/TfsEnricher.cs b/src/Spectre.Console/Enrichment/CI/TfsEnricher.cs index 3bb5068..9dac0b5 100644 --- a/src/Spectre.Console/Enrichment/CI/TfsEnricher.cs +++ b/src/Spectre.Console/Enrichment/CI/TfsEnricher.cs @@ -1,19 +1,18 @@ using System.Collections.Generic; -namespace Spectre.Console.Enrichment +namespace Spectre.Console.Enrichment; + +internal sealed class TfsEnricher : IProfileEnricher { - internal sealed class TfsEnricher : IProfileEnricher + public string Name => "TFS"; + + public bool Enabled(IDictionary environmentVariables) { - public string Name => "TFS"; - - public bool Enabled(IDictionary environmentVariables) - { - return environmentVariables.ContainsKey("TF_BUILD"); - } - - public void Enrich(Profile profile) - { - profile.Capabilities.Interactive = false; - } + return environmentVariables.ContainsKey("TF_BUILD"); } -} + + public void Enrich(Profile profile) + { + profile.Capabilities.Interactive = false; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Enrichment/CI/TravisEnricher.cs b/src/Spectre.Console/Enrichment/CI/TravisEnricher.cs index 46f6528..526bc18 100644 --- a/src/Spectre.Console/Enrichment/CI/TravisEnricher.cs +++ b/src/Spectre.Console/Enrichment/CI/TravisEnricher.cs @@ -1,19 +1,18 @@ using System.Collections.Generic; -namespace Spectre.Console.Enrichment +namespace Spectre.Console.Enrichment; + +internal sealed class TravisEnricher : IProfileEnricher { - internal sealed class TravisEnricher : IProfileEnricher + public string Name => "Travis"; + + public bool Enabled(IDictionary environmentVariables) { - public string Name => "Travis"; - - public bool Enabled(IDictionary environmentVariables) - { - return environmentVariables.ContainsKey("TRAVIS"); - } - - public void Enrich(Profile profile) - { - profile.Capabilities.Interactive = false; - } + return environmentVariables.ContainsKey("TRAVIS"); } -} + + public void Enrich(Profile profile) + { + profile.Capabilities.Interactive = false; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Enrichment/ProfileEnricher.cs b/src/Spectre.Console/Enrichment/ProfileEnricher.cs index 4b7b592..e2062a8 100644 --- a/src/Spectre.Console/Enrichment/ProfileEnricher.cs +++ b/src/Spectre.Console/Enrichment/ProfileEnricher.cs @@ -2,11 +2,11 @@ using System; using System.Collections.Generic; using System.Linq; -namespace Spectre.Console.Enrichment +namespace Spectre.Console.Enrichment; + +internal static class ProfileEnricher { - internal static class ProfileEnricher - { - private static readonly List _defaultEnrichers = new List + private static readonly List _defaultEnrichers = new List { new AppVeyorEnricher(), new BambooEnricher(), @@ -23,73 +23,72 @@ namespace Spectre.Console.Enrichment new TravisEnricher(), }; - public static void Enrich( - Profile profile, - ProfileEnrichment settings, - IDictionary? environmentVariables) + public static void Enrich( + Profile profile, + ProfileEnrichment settings, + IDictionary? environmentVariables) + { + if (profile is null) { - if (profile is null) - { - throw new ArgumentNullException(nameof(profile)); - } - - settings ??= new ProfileEnrichment(); - - var variables = GetEnvironmentVariables(environmentVariables); - foreach (var enricher in GetEnrichers(settings)) - { - if (string.IsNullOrWhiteSpace(enricher.Name)) - { - throw new InvalidOperationException($"Profile enricher of type '{enricher.GetType().FullName}' does not have a name."); - } - - if (enricher.Enabled(variables)) - { - enricher.Enrich(profile); - profile.AddEnricher(enricher.Name); - } - } + throw new ArgumentNullException(nameof(profile)); } - private static List GetEnrichers(ProfileEnrichment settings) + settings ??= new ProfileEnrichment(); + + var variables = GetEnvironmentVariables(environmentVariables); + foreach (var enricher in GetEnrichers(settings)) { - var enrichers = new List(); - - if (settings.UseDefaultEnrichers) + if (string.IsNullOrWhiteSpace(enricher.Name)) { - enrichers.AddRange(_defaultEnrichers); + throw new InvalidOperationException($"Profile enricher of type '{enricher.GetType().FullName}' does not have a name."); } - if (settings.Enrichers?.Count > 0) + if (enricher.Enabled(variables)) { - enrichers.AddRange(settings.Enrichers); + enricher.Enrich(profile); + profile.AddEnricher(enricher.Name); } - - return enrichers; - } - - private static IDictionary GetEnvironmentVariables(IDictionary? variables) - { - if (variables != null) - { - return new Dictionary(variables, StringComparer.OrdinalIgnoreCase); - } - - return Environment.GetEnvironmentVariables() - .Cast() - .Aggregate( - new Dictionary(StringComparer.OrdinalIgnoreCase), - (dictionary, entry) => - { - var key = (string)entry.Key; - if (!dictionary.TryGetValue(key, out _)) - { - dictionary.Add(key, entry.Value as string ?? string.Empty); - } - - return dictionary; - }, - dictionary => dictionary); } } -} + + private static List GetEnrichers(ProfileEnrichment settings) + { + var enrichers = new List(); + + if (settings.UseDefaultEnrichers) + { + enrichers.AddRange(_defaultEnrichers); + } + + if (settings.Enrichers?.Count > 0) + { + enrichers.AddRange(settings.Enrichers); + } + + return enrichers; + } + + private static IDictionary GetEnvironmentVariables(IDictionary? variables) + { + if (variables != null) + { + return new Dictionary(variables, StringComparer.OrdinalIgnoreCase); + } + + return Environment.GetEnvironmentVariables() + .Cast() + .Aggregate( + new Dictionary(StringComparer.OrdinalIgnoreCase), + (dictionary, entry) => + { + var key = (string)entry.Key; + if (!dictionary.TryGetValue(key, out _)) + { + dictionary.Add(key, entry.Value as string ?? string.Empty); + } + + return dictionary; + }, + dictionary => dictionary); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Enrichment/ProfileEnrichment.cs b/src/Spectre.Console/Enrichment/ProfileEnrichment.cs index 7d43e8f..e72dd62 100644 --- a/src/Spectre.Console/Enrichment/ProfileEnrichment.cs +++ b/src/Spectre.Console/Enrichment/ProfileEnrichment.cs @@ -1,22 +1,21 @@ using System.Collections.Generic; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains settings for profile enrichment. +/// +public sealed class ProfileEnrichment { /// - /// Contains settings for profile enrichment. + /// Gets or sets a value indicating whether or not + /// any default enrichers should be added. /// - public sealed class ProfileEnrichment - { - /// - /// Gets or sets a value indicating whether or not - /// any default enrichers should be added. - /// - /// Defaults to true. - public bool UseDefaultEnrichers { get; set; } = true; + /// Defaults to true. + public bool UseDefaultEnrichers { get; set; } = true; - /// - /// Gets or sets the list of custom enrichers to use. - /// - public List? Enrichers { get; set; } - } -} + /// + /// Gets or sets the list of custom enrichers to use. + /// + public List? Enrichers { get; set; } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/Advanced/AnsiConsoleExtensions.cs b/src/Spectre.Console/Extensions/Advanced/AnsiConsoleExtensions.cs index 1962088..12a3cd7 100644 --- a/src/Spectre.Console/Extensions/Advanced/AnsiConsoleExtensions.cs +++ b/src/Spectre.Console/Extensions/Advanced/AnsiConsoleExtensions.cs @@ -1,40 +1,39 @@ using System; using Spectre.Console.Rendering; -namespace Spectre.Console.Advanced +namespace Spectre.Console.Advanced; + +/// +/// Contains extension methods for . +/// +public static class AnsiConsoleExtensions { /// - /// Contains extension methods for . + /// Writes a VT/Ansi control code sequence to the console (if supported). /// - public static class AnsiConsoleExtensions + /// The console to write to. + /// The VT/Ansi control code sequence to write. + public static void WriteAnsi(this IAnsiConsole console, string sequence) { - /// - /// Writes a VT/Ansi control code sequence to the console (if supported). - /// - /// The console to write to. - /// The VT/Ansi control code sequence to write. - public static void WriteAnsi(this IAnsiConsole console, string sequence) + if (console is null) { - if (console is null) - { - throw new ArgumentNullException(nameof(console)); - } - - if (console.Profile.Capabilities.Ansi) - { - console.Write(new ControlCode(sequence)); - } + throw new ArgumentNullException(nameof(console)); } - /// - /// Gets the VT/ANSI control code sequence for a . - /// - /// The console. - /// The renderable to the VT/ANSI control code sequence for. - /// The VT/ANSI control code sequence. - public static string ToAnsi(this IAnsiConsole console, IRenderable renderable) + if (console.Profile.Capabilities.Ansi) { - return AnsiBuilder.Build(console, renderable); + console.Write(new ControlCode(sequence)); } } -} + + /// + /// Gets the VT/ANSI control code sequence for a . + /// + /// The console. + /// The renderable to the VT/ANSI control code sequence for. + /// The VT/ANSI control code sequence. + public static string ToAnsi(this IAnsiConsole console, IRenderable renderable) + { + return AnsiBuilder.Build(console, renderable); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/AlignableExtensions.cs b/src/Spectre.Console/Extensions/AlignableExtensions.cs index 05693ae..4efc934 100644 --- a/src/Spectre.Console/Extensions/AlignableExtensions.cs +++ b/src/Spectre.Console/Extensions/AlignableExtensions.cs @@ -1,81 +1,80 @@ -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class AlignableExtensions { /// - /// Contains extension methods for . + /// Sets the alignment for an object. /// - public static class AlignableExtensions + /// The alignable object type. + /// The alignable object. + /// The alignment. + /// The same instance so that multiple calls can be chained. + public static T Alignment(this T obj, Justify? alignment) + where T : class, IAlignable { - /// - /// Sets the alignment for an object. - /// - /// The alignable object type. - /// The alignable object. - /// The alignment. - /// The same instance so that multiple calls can be chained. - public static T Alignment(this T obj, Justify? alignment) - where T : class, IAlignable + if (obj is null) { - if (obj is null) - { - throw new System.ArgumentNullException(nameof(obj)); - } - - obj.Alignment = alignment; - return obj; + throw new System.ArgumentNullException(nameof(obj)); } - /// - /// Sets the object to be left aligned. - /// - /// The alignable type. - /// The alignable object. - /// The same instance so that multiple calls can be chained. - public static T LeftAligned(this T obj) - where T : class, IAlignable - { - if (obj is null) - { - throw new System.ArgumentNullException(nameof(obj)); - } - - obj.Alignment = Justify.Left; - return obj; - } - - /// - /// Sets the object to be centered. - /// - /// The alignable type. - /// The alignable object. - /// The same instance so that multiple calls can be chained. - public static T Centered(this T obj) - where T : class, IAlignable - { - if (obj is null) - { - throw new System.ArgumentNullException(nameof(obj)); - } - - obj.Alignment = Justify.Center; - return obj; - } - - /// - /// Sets the object to be right aligned. - /// - /// The alignable type. - /// The alignable object. - /// The same instance so that multiple calls can be chained. - public static T RightAligned(this T obj) - where T : class, IAlignable - { - if (obj is null) - { - throw new System.ArgumentNullException(nameof(obj)); - } - - obj.Alignment = Justify.Right; - return obj; - } + obj.Alignment = alignment; + return obj; } -} + + /// + /// Sets the object to be left aligned. + /// + /// The alignable type. + /// The alignable object. + /// The same instance so that multiple calls can be chained. + public static T LeftAligned(this T obj) + where T : class, IAlignable + { + if (obj is null) + { + throw new System.ArgumentNullException(nameof(obj)); + } + + obj.Alignment = Justify.Left; + return obj; + } + + /// + /// Sets the object to be centered. + /// + /// The alignable type. + /// The alignable object. + /// The same instance so that multiple calls can be chained. + public static T Centered(this T obj) + where T : class, IAlignable + { + if (obj is null) + { + throw new System.ArgumentNullException(nameof(obj)); + } + + obj.Alignment = Justify.Center; + return obj; + } + + /// + /// Sets the object to be right aligned. + /// + /// The alignable type. + /// The alignable object. + /// The same instance so that multiple calls can be chained. + public static T RightAligned(this T obj) + where T : class, IAlignable + { + if (obj is null) + { + throw new System.ArgumentNullException(nameof(obj)); + } + + obj.Alignment = Justify.Right; + return obj; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Exceptions.cs b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Exceptions.cs index fa6bdc7..3676111 100644 --- a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Exceptions.cs +++ b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Exceptions.cs @@ -1,32 +1,31 @@ using System; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static partial class AnsiConsoleExtensions { /// - /// Contains extension methods for . + /// Writes an exception to the console. /// - public static partial class AnsiConsoleExtensions + /// The console. + /// The exception to write to the console. + /// The exception format options. + public static void WriteException(this IAnsiConsole console, Exception exception, ExceptionFormats format = ExceptionFormats.Default) { - /// - /// Writes an exception to the console. - /// - /// The console. - /// The exception to write to the console. - /// The exception format options. - public static void WriteException(this IAnsiConsole console, Exception exception, ExceptionFormats format = ExceptionFormats.Default) - { - console.Write(exception.GetRenderable(format)); - } - - /// - /// Writes an exception to the console. - /// - /// The console. - /// The exception to write to the console. - /// The exception settings. - public static void WriteException(this IAnsiConsole console, Exception exception, ExceptionSettings settings) - { - console.Write(exception.GetRenderable(settings)); - } + console.Write(exception.GetRenderable(format)); } -} + + /// + /// Writes an exception to the console. + /// + /// The console. + /// The exception to write to the console. + /// The exception settings. + public static void WriteException(this IAnsiConsole console, Exception exception, ExceptionSettings settings) + { + console.Write(exception.GetRenderable(settings)); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Exclusive.cs b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Exclusive.cs index 0bdc535..ffcd9da 100644 --- a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Exclusive.cs +++ b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Exclusive.cs @@ -1,35 +1,34 @@ using System; using System.Threading.Tasks; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static partial class AnsiConsoleExtensions { /// - /// Contains extension methods for . + /// Runs the specified function in exclusive mode. /// - public static partial class AnsiConsoleExtensions + /// The result type. + /// The console. + /// The func to run in exclusive mode. + /// The result of the function. + public static T RunExclusive(this IAnsiConsole console, Func func) { - /// - /// Runs the specified function in exclusive mode. - /// - /// The result type. - /// The console. - /// The func to run in exclusive mode. - /// The result of the function. - public static T RunExclusive(this IAnsiConsole console, Func func) - { - return console.ExclusivityMode.Run(func); - } - - /// - /// Runs the specified function in exclusive mode asynchronously. - /// - /// The result type. - /// The console. - /// The func to run in exclusive mode. - /// The result of the function. - public static Task RunExclusive(this IAnsiConsole console, Func> func) - { - return console.ExclusivityMode.RunAsync(func); - } + return console.ExclusivityMode.Run(func); } -} + + /// + /// Runs the specified function in exclusive mode asynchronously. + /// + /// The result type. + /// The console. + /// The func to run in exclusive mode. + /// The result of the function. + public static Task RunExclusive(this IAnsiConsole console, Func> func) + { + return console.ExclusivityMode.RunAsync(func); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Input.cs b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Input.cs index 07109cb..de634d7 100644 --- a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Input.cs +++ b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Input.cs @@ -5,103 +5,102 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static partial class AnsiConsoleExtensions { - /// - /// Contains extension methods for . - /// - public static partial class AnsiConsoleExtensions + internal static async Task ReadLine(this IAnsiConsole console, Style? style, bool secret, IEnumerable? items = null, CancellationToken cancellationToken = default) { - internal static async Task ReadLine(this IAnsiConsole console, Style? style, bool secret, IEnumerable? items = null, CancellationToken cancellationToken = default) + if (console is null) { - if (console is null) - { - throw new ArgumentNullException(nameof(console)); - } - - style ??= Style.Plain; - var text = string.Empty; - - var autocomplete = new List(items ?? Enumerable.Empty()); - - while (true) - { - var rawKey = await console.Input.ReadKeyAsync(true, cancellationToken).ConfigureAwait(false); - if (rawKey == null) - { - continue; - } - - var key = rawKey.Value; - if (key.Key == ConsoleKey.Enter) - { - return text; - } - - if (key.Key == ConsoleKey.Tab && autocomplete.Count > 0) - { - var replace = AutoComplete(autocomplete, text); - if (!string.IsNullOrEmpty(replace)) - { - // Render the suggestion - console.Write("\b \b".Repeat(text.Length), style); - console.Write(replace); - text = replace; - continue; - } - } - - if (key.Key == ConsoleKey.Backspace) - { - if (text.Length > 0) - { - text = text.Substring(0, text.Length - 1); - console.Write("\b \b"); - } - - continue; - } - - if (!char.IsControl(key.KeyChar)) - { - text += key.KeyChar.ToString(); - console.Write(secret ? "*" : key.KeyChar.ToString(), style); - } - } + throw new ArgumentNullException(nameof(console)); } - private static string AutoComplete(List autocomplete, string text) + style ??= Style.Plain; + var text = string.Empty; + + var autocomplete = new List(items ?? Enumerable.Empty()); + + while (true) { - var found = autocomplete.Find(i => i == text); - var replace = string.Empty; - - if (found == null) + var rawKey = await console.Input.ReadKeyAsync(true, cancellationToken).ConfigureAwait(false); + if (rawKey == null) { - // Get the closest match - var next = autocomplete.Find(i => i.StartsWith(text, true, CultureInfo.InvariantCulture)); - if (next != null) - { - replace = next; - } - else if (string.IsNullOrEmpty(text)) - { - // Use the first item - replace = autocomplete[0]; - } - } - else - { - // Get the next match - var index = autocomplete.IndexOf(found) + 1; - if (index >= autocomplete.Count) - { - index = 0; - } - - replace = autocomplete[index]; + continue; } - return replace; + var key = rawKey.Value; + if (key.Key == ConsoleKey.Enter) + { + return text; + } + + if (key.Key == ConsoleKey.Tab && autocomplete.Count > 0) + { + var replace = AutoComplete(autocomplete, text); + if (!string.IsNullOrEmpty(replace)) + { + // Render the suggestion + console.Write("\b \b".Repeat(text.Length), style); + console.Write(replace); + text = replace; + continue; + } + } + + if (key.Key == ConsoleKey.Backspace) + { + if (text.Length > 0) + { + text = text.Substring(0, text.Length - 1); + console.Write("\b \b"); + } + + continue; + } + + if (!char.IsControl(key.KeyChar)) + { + text += key.KeyChar.ToString(); + console.Write(secret ? "*" : key.KeyChar.ToString(), style); + } } } -} + + private static string AutoComplete(List autocomplete, string text) + { + var found = autocomplete.Find(i => i == text); + var replace = string.Empty; + + if (found == null) + { + // Get the closest match + var next = autocomplete.Find(i => i.StartsWith(text, true, CultureInfo.InvariantCulture)); + if (next != null) + { + replace = next; + } + else if (string.IsNullOrEmpty(text)) + { + // Use the first item + replace = autocomplete[0]; + } + } + else + { + // Get the next match + var index = autocomplete.IndexOf(found) + 1; + if (index >= autocomplete.Count) + { + index = 0; + } + + replace = autocomplete[index]; + } + + return replace; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Live.cs b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Live.cs index a5b1a6f..d954331 100644 --- a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Live.cs +++ b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Live.cs @@ -1,32 +1,31 @@ using System; using Spectre.Console.Rendering; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static partial class AnsiConsoleExtensions { /// - /// Contains extension methods for . + /// Creates a new instance for the console. /// - public static partial class AnsiConsoleExtensions + /// The console. + /// The target renderable to update. + /// A instance. + public static LiveDisplay Live(this IAnsiConsole console, IRenderable target) { - /// - /// Creates a new instance for the console. - /// - /// The console. - /// The target renderable to update. - /// A instance. - public static LiveDisplay Live(this IAnsiConsole console, IRenderable target) + if (console is null) { - if (console is null) - { - throw new ArgumentNullException(nameof(console)); - } - - if (target is null) - { - throw new ArgumentNullException(nameof(target)); - } - - return new LiveDisplay(console, target); + throw new ArgumentNullException(nameof(console)); } + + if (target is null) + { + throw new ArgumentNullException(nameof(target)); + } + + return new LiveDisplay(console, target); } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Markup.cs b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Markup.cs index 1f2f8a9..de3b073 100644 --- a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Markup.cs +++ b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Markup.cs @@ -1,77 +1,76 @@ using System; using System.Globalization; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static partial class AnsiConsoleExtensions { /// - /// Contains extension methods for . + /// Writes the specified markup to the console. /// - public static partial class AnsiConsoleExtensions + /// The console to write to. + /// A composite format string. + /// An array of objects to write. + public static void Markup(this IAnsiConsole console, string format, params object[] args) { - /// - /// Writes the specified markup to the console. - /// - /// The console to write to. - /// A composite format string. - /// An array of objects to write. - public static void Markup(this IAnsiConsole console, string format, params object[] args) - { - Markup(console, CultureInfo.CurrentCulture, format, args); - } + Markup(console, CultureInfo.CurrentCulture, format, args); + } - /// - /// Writes the specified markup to the console. - /// - /// The console to write to. - /// An object that supplies culture-specific formatting information. - /// A composite format string. - /// An array of objects to write. - public static void Markup(this IAnsiConsole console, IFormatProvider provider, string format, params object[] args) - { - Markup(console, string.Format(provider, format, args)); - } + /// + /// Writes the specified markup to the console. + /// + /// The console to write to. + /// An object that supplies culture-specific formatting information. + /// A composite format string. + /// An array of objects to write. + public static void Markup(this IAnsiConsole console, IFormatProvider provider, string format, params object[] args) + { + Markup(console, string.Format(provider, format, args)); + } - /// - /// Writes the specified markup to the console. - /// - /// The console to write to. - /// The value to write. - public static void Markup(this IAnsiConsole console, string value) - { - console.Write(MarkupParser.Parse(value)); - } + /// + /// Writes the specified markup to the console. + /// + /// The console to write to. + /// The value to write. + public static void Markup(this IAnsiConsole console, string value) + { + console.Write(MarkupParser.Parse(value)); + } - /// - /// Writes the specified markup, followed by the current line terminator, to the console. - /// - /// The console to write to. - /// A composite format string. - /// An array of objects to write. - public static void MarkupLine(this IAnsiConsole console, string format, params object[] args) - { - MarkupLine(console, CultureInfo.CurrentCulture, format, args); - } + /// + /// Writes the specified markup, followed by the current line terminator, to the console. + /// + /// The console to write to. + /// A composite format string. + /// An array of objects to write. + public static void MarkupLine(this IAnsiConsole console, string format, params object[] args) + { + MarkupLine(console, CultureInfo.CurrentCulture, format, args); + } - /// - /// Writes the specified markup, followed by the current line terminator, to the console. - /// - /// The console to write to. - /// The value to write. - public static void MarkupLine(this IAnsiConsole console, string value) - { - Markup(console, value + Environment.NewLine); - } + /// + /// Writes the specified markup, followed by the current line terminator, to the console. + /// + /// The console to write to. + /// The value to write. + public static void MarkupLine(this IAnsiConsole console, string value) + { + Markup(console, value + Environment.NewLine); + } - /// - /// Writes the specified markup, followed by the current line terminator, to the console. - /// - /// The console to write to. - /// An object that supplies culture-specific formatting information. - /// A composite format string. - /// An array of objects to write. - public static void MarkupLine(this IAnsiConsole console, IFormatProvider provider, string format, params object[] args) - { - Markup(console, provider, format + Environment.NewLine, args); - } + /// + /// Writes the specified markup, followed by the current line terminator, to the console. + /// + /// The console to write to. + /// An object that supplies culture-specific formatting information. + /// A composite format string. + /// An array of objects to write. + public static void MarkupLine(this IAnsiConsole console, IFormatProvider provider, string format, params object[] args) + { + Markup(console, provider, format + Environment.NewLine, args); } } \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Progress.cs b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Progress.cs index 1868d4c..d9daf78 100644 --- a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Progress.cs +++ b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Progress.cs @@ -1,40 +1,39 @@ using System; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static partial class AnsiConsoleExtensions { /// - /// Contains extension methods for . + /// Creates a new instance for the console. /// - public static partial class AnsiConsoleExtensions + /// The console. + /// A instance. + public static Progress Progress(this IAnsiConsole console) { - /// - /// Creates a new instance for the console. - /// - /// The console. - /// A instance. - public static Progress Progress(this IAnsiConsole console) + if (console is null) { - if (console is null) - { - throw new ArgumentNullException(nameof(console)); - } - - return new Progress(console); + throw new ArgumentNullException(nameof(console)); } - /// - /// Creates a new instance for the console. - /// - /// The console. - /// A instance. - public static Status Status(this IAnsiConsole console) - { - if (console is null) - { - throw new ArgumentNullException(nameof(console)); - } - - return new Status(console); - } + return new Progress(console); } -} + + /// + /// Creates a new instance for the console. + /// + /// The console. + /// A instance. + public static Status Status(this IAnsiConsole console) + { + if (console is null) + { + throw new ArgumentNullException(nameof(console)); + } + + return new Status(console); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Prompt.cs b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Prompt.cs index 07fd3c7..9eed583 100644 --- a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Prompt.cs +++ b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Prompt.cs @@ -1,55 +1,54 @@ using System; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static partial class AnsiConsoleExtensions { /// - /// Contains extension methods for . + /// Displays a prompt to the user. /// - public static partial class AnsiConsoleExtensions + /// The prompt result type. + /// The console. + /// The prompt to display. + /// The prompt input result. + public static T Prompt(this IAnsiConsole console, IPrompt prompt) { - /// - /// Displays a prompt to the user. - /// - /// The prompt result type. - /// The console. - /// The prompt to display. - /// The prompt input result. - public static T Prompt(this IAnsiConsole console, IPrompt prompt) + if (prompt is null) { - if (prompt is null) - { - throw new ArgumentNullException(nameof(prompt)); - } - - return prompt.Show(console); + throw new ArgumentNullException(nameof(prompt)); } - /// - /// Displays a prompt to the user. - /// - /// The prompt result type. - /// The console. - /// The prompt markup text. - /// The prompt input result. - public static T Ask(this IAnsiConsole console, string prompt) - { - return new TextPrompt(prompt).Show(console); - } - - /// - /// Displays a prompt with two choices, yes or no. - /// - /// The console. - /// The prompt markup text. - /// Specifies the default answer. - /// true if the user selected "yes", otherwise false. - public static bool Confirm(this IAnsiConsole console, string prompt, bool defaultValue = true) - { - return new ConfirmationPrompt(prompt) - { - DefaultValue = defaultValue, - } - .Show(console); - } + return prompt.Show(console); } -} + + /// + /// Displays a prompt to the user. + /// + /// The prompt result type. + /// The console. + /// The prompt markup text. + /// The prompt input result. + public static T Ask(this IAnsiConsole console, string prompt) + { + return new TextPrompt(prompt).Show(console); + } + + /// + /// Displays a prompt with two choices, yes or no. + /// + /// The console. + /// The prompt markup text. + /// Specifies the default answer. + /// true if the user selected "yes", otherwise false. + public static bool Confirm(this IAnsiConsole console, string prompt, bool defaultValue = true) + { + return new ConfirmationPrompt(prompt) + { + DefaultValue = defaultValue, + } + .Show(console); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Rendering.cs b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Rendering.cs index 020f101..254e542 100644 --- a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Rendering.cs +++ b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Rendering.cs @@ -1,32 +1,31 @@ using System; using Spectre.Console.Rendering; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static partial class AnsiConsoleExtensions { /// - /// Contains extension methods for . + /// Renders the specified object to the console. /// - public static partial class AnsiConsoleExtensions + /// The console to render to. + /// The object to render. + [Obsolete("Consider using IAnsiConsole.Write instead.")] + public static void Render(this IAnsiConsole console, IRenderable renderable) { - /// - /// Renders the specified object to the console. - /// - /// The console to render to. - /// The object to render. - [Obsolete("Consider using IAnsiConsole.Write instead.")] - public static void Render(this IAnsiConsole console, IRenderable renderable) + if (console is null) { - if (console is null) - { - throw new ArgumentNullException(nameof(console)); - } - - if (renderable is null) - { - throw new ArgumentNullException(nameof(renderable)); - } - - console.Write(renderable); + throw new ArgumentNullException(nameof(console)); } + + if (renderable is null) + { + throw new ArgumentNullException(nameof(renderable)); + } + + console.Write(renderable); } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Screen.cs b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Screen.cs index 1491bfb..7f9385e 100644 --- a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Screen.cs +++ b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.Screen.cs @@ -1,48 +1,47 @@ using System; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static partial class AnsiConsoleExtensions { /// - /// Contains extension methods for . + /// Switches to an alternate screen buffer if the terminal supports it. /// - public static partial class AnsiConsoleExtensions + /// The console. + /// The action to execute within the alternate screen buffer. + public static void AlternateScreen(this IAnsiConsole console, Action action) { - /// - /// Switches to an alternate screen buffer if the terminal supports it. - /// - /// The console. - /// The action to execute within the alternate screen buffer. - public static void AlternateScreen(this IAnsiConsole console, Action action) + if (console is null) { - if (console is null) - { - throw new ArgumentNullException(nameof(console)); - } - - if (!console.Profile.Capabilities.Ansi) - { - throw new NotSupportedException("Alternate buffers are not supported since your terminal does not support ANSI."); - } - - if (!console.Profile.Capabilities.AlternateBuffer) - { - throw new NotSupportedException("Alternate buffers are not supported by your terminal."); - } - - console.ExclusivityMode.Run(() => - { - // Switch to alternate screen - console.Write(new ControlCode("\u001b[?1049h\u001b[H")); - - // Execute custom action - action(); - - // Switch back to primary screen - console.Write(new ControlCode("\u001b[?1049l")); - - // Dummy result - return null; - }); + throw new ArgumentNullException(nameof(console)); } + + if (!console.Profile.Capabilities.Ansi) + { + throw new NotSupportedException("Alternate buffers are not supported since your terminal does not support ANSI."); + } + + if (!console.Profile.Capabilities.AlternateBuffer) + { + throw new NotSupportedException("Alternate buffers are not supported by your terminal."); + } + + console.ExclusivityMode.Run(() => + { + // Switch to alternate screen + console.Write(new ControlCode("\u001b[?1049h\u001b[H")); + + // Execute custom action + action(); + + // Switch back to primary screen + console.Write(new ControlCode("\u001b[?1049l")); + + // Dummy result + return null; + }); } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.cs b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.cs index 92c57e4..74f3bf9 100644 --- a/src/Spectre.Console/Extensions/AnsiConsoleExtensions.cs +++ b/src/Spectre.Console/Extensions/AnsiConsoleExtensions.cs @@ -1,110 +1,109 @@ using System; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static partial class AnsiConsoleExtensions { /// - /// Contains extension methods for . + /// Creates a recorder for the specified console. /// - public static partial class AnsiConsoleExtensions + /// The console to record. + /// A recorder for the specified console. + public static Recorder CreateRecorder(this IAnsiConsole console) { - /// - /// Creates a recorder for the specified console. - /// - /// The console to record. - /// A recorder for the specified console. - public static Recorder CreateRecorder(this IAnsiConsole console) - { - return new Recorder(console); - } - - /// - /// Clears the console. - /// - /// The console to clear. - public static void Clear(this IAnsiConsole console) - { - if (console is null) - { - throw new ArgumentNullException(nameof(console)); - } - - console.Clear(true); - } - - /// - /// Writes the specified string value to the console. - /// - /// The console to write to. - /// The text to write. - public static void Write(this IAnsiConsole console, string text) - { - if (console is null) - { - throw new ArgumentNullException(nameof(console)); - } - - console.Write(new Text(text, Style.Plain)); - } - - /// - /// Writes the specified string value to the console. - /// - /// The console to write to. - /// The text to write. - /// The text style or if . - public static void Write(this IAnsiConsole console, string text, Style? style) - { - if (console is null) - { - throw new ArgumentNullException(nameof(console)); - } - - console.Write(new Text(text, style)); - } - - /// - /// Writes an empty line to the console. - /// - /// The console to write to. - public static void WriteLine(this IAnsiConsole console) - { - if (console is null) - { - throw new ArgumentNullException(nameof(console)); - } - - console.Write(Text.NewLine); - } - - /// - /// Writes the specified string value, followed by the current line terminator, to the console. - /// - /// The console to write to. - /// The text to write. - public static void WriteLine(this IAnsiConsole console, string text) - { - WriteLine(console, text, Style.Plain); - } - - /// - /// Writes the specified string value, followed by the current line terminator, to the console. - /// - /// The console to write to. - /// The text to write. - /// The text style or if . - public static void WriteLine(this IAnsiConsole console, string text, Style? style) - { - if (console is null) - { - throw new ArgumentNullException(nameof(console)); - } - - if (text is null) - { - throw new ArgumentNullException(nameof(text)); - } - - console.Write(text + Environment.NewLine, style); - } + return new Recorder(console); } -} + + /// + /// Clears the console. + /// + /// The console to clear. + public static void Clear(this IAnsiConsole console) + { + if (console is null) + { + throw new ArgumentNullException(nameof(console)); + } + + console.Clear(true); + } + + /// + /// Writes the specified string value to the console. + /// + /// The console to write to. + /// The text to write. + public static void Write(this IAnsiConsole console, string text) + { + if (console is null) + { + throw new ArgumentNullException(nameof(console)); + } + + console.Write(new Text(text, Style.Plain)); + } + + /// + /// Writes the specified string value to the console. + /// + /// The console to write to. + /// The text to write. + /// The text style or if . + public static void Write(this IAnsiConsole console, string text, Style? style) + { + if (console is null) + { + throw new ArgumentNullException(nameof(console)); + } + + console.Write(new Text(text, style)); + } + + /// + /// Writes an empty line to the console. + /// + /// The console to write to. + public static void WriteLine(this IAnsiConsole console) + { + if (console is null) + { + throw new ArgumentNullException(nameof(console)); + } + + console.Write(Text.NewLine); + } + + /// + /// Writes the specified string value, followed by the current line terminator, to the console. + /// + /// The console to write to. + /// The text to write. + public static void WriteLine(this IAnsiConsole console, string text) + { + WriteLine(console, text, Style.Plain); + } + + /// + /// Writes the specified string value, followed by the current line terminator, to the console. + /// + /// The console to write to. + /// The text to write. + /// The text style or if . + public static void WriteLine(this IAnsiConsole console, string text, Style? style) + { + if (console is null) + { + throw new ArgumentNullException(nameof(console)); + } + + if (text is null) + { + throw new ArgumentNullException(nameof(text)); + } + + console.Write(text + Environment.NewLine, style); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/BarChartExtensions.cs b/src/Spectre.Console/Extensions/BarChartExtensions.cs index 22f8884..b89b553 100644 --- a/src/Spectre.Console/Extensions/BarChartExtensions.cs +++ b/src/Spectre.Console/Extensions/BarChartExtensions.cs @@ -1,259 +1,258 @@ using System; using System.Collections.Generic; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class BarChartExtensions { /// - /// Contains extension methods for . + /// Adds an item to the bar chart. /// - public static class BarChartExtensions + /// The bar chart. + /// The item label. + /// The item value. + /// The item color. + /// The same instance so that multiple calls can be chained. + public static BarChart AddItem(this BarChart chart, string label, double value, Color? color = null) { - /// - /// Adds an item to the bar chart. - /// - /// The bar chart. - /// The item label. - /// The item value. - /// The item color. - /// The same instance so that multiple calls can be chained. - public static BarChart AddItem(this BarChart chart, string label, double value, Color? color = null) + if (chart is null) { - if (chart is null) - { - throw new ArgumentNullException(nameof(chart)); - } - - chart.Data.Add(new BarChartItem(label, value, color)); - return chart; + throw new ArgumentNullException(nameof(chart)); } - /// - /// Adds an item to the bar chart. - /// - /// A type that implements . - /// The bar chart. - /// The item. - /// The same instance so that multiple calls can be chained. - public static BarChart AddItem(this BarChart chart, T item) - where T : IBarChartItem + chart.Data.Add(new BarChartItem(label, value, color)); + return chart; + } + + /// + /// Adds an item to the bar chart. + /// + /// A type that implements . + /// The bar chart. + /// The item. + /// The same instance so that multiple calls can be chained. + public static BarChart AddItem(this BarChart chart, T item) + where T : IBarChartItem + { + if (chart is null) { - if (chart is null) - { - throw new ArgumentNullException(nameof(chart)); - } - - if (item is BarChartItem barChartItem) - { - chart.Data.Add(barChartItem); - } - else - { - chart.Data.Add( - new BarChartItem( - item.Label, - item.Value, - item.Color)); - } - - return chart; + throw new ArgumentNullException(nameof(chart)); } - /// - /// Adds multiple items to the bar chart. - /// - /// A type that implements . - /// The bar chart. - /// The items. - /// The same instance so that multiple calls can be chained. - public static BarChart AddItems(this BarChart chart, IEnumerable items) - where T : IBarChartItem + if (item is BarChartItem barChartItem) { - if (chart is null) - { - throw new ArgumentNullException(nameof(chart)); - } - - if (items is null) - { - throw new ArgumentNullException(nameof(items)); - } - - foreach (var item in items) - { - AddItem(chart, item); - } - - return chart; + chart.Data.Add(barChartItem); + } + else + { + chart.Data.Add( + new BarChartItem( + item.Label, + item.Value, + item.Color)); } - /// - /// Adds multiple items to the bar chart. - /// - /// A type that implements . - /// The bar chart. - /// The items. - /// The converter that converts instances of T to . - /// The same instance so that multiple calls can be chained. - public static BarChart AddItems(this BarChart chart, IEnumerable items, Func converter) + return chart; + } + + /// + /// Adds multiple items to the bar chart. + /// + /// A type that implements . + /// The bar chart. + /// The items. + /// The same instance so that multiple calls can be chained. + public static BarChart AddItems(this BarChart chart, IEnumerable items) + where T : IBarChartItem + { + if (chart is null) { - if (chart is null) - { - throw new ArgumentNullException(nameof(chart)); - } - - if (items is null) - { - throw new ArgumentNullException(nameof(items)); - } - - if (converter is null) - { - throw new ArgumentNullException(nameof(converter)); - } - - foreach (var item in items) - { - chart.Data.Add(converter(item)); - } - - return chart; + throw new ArgumentNullException(nameof(chart)); } - /// - /// Sets the width of the bar chart. - /// - /// The bar chart. - /// The bar chart width. - /// The same instance so that multiple calls can be chained. - public static BarChart Width(this BarChart chart, int? width) + if (items is null) { - if (chart is null) - { - throw new ArgumentNullException(nameof(chart)); - } - - chart.Width = width; - return chart; + throw new ArgumentNullException(nameof(items)); } - /// - /// Sets the label of the bar chart. - /// - /// The bar chart. - /// The bar chart label. - /// The same instance so that multiple calls can be chained. - public static BarChart Label(this BarChart chart, string? label) + foreach (var item in items) { - if (chart is null) - { - throw new ArgumentNullException(nameof(chart)); - } - - chart.Label = label; - return chart; + AddItem(chart, item); } - /// - /// Shows values next to each bar in the bar chart. - /// - /// The bar chart. - /// The same instance so that multiple calls can be chained. - public static BarChart ShowValues(this BarChart chart) + return chart; + } + + /// + /// Adds multiple items to the bar chart. + /// + /// A type that implements . + /// The bar chart. + /// The items. + /// The converter that converts instances of T to . + /// The same instance so that multiple calls can be chained. + public static BarChart AddItems(this BarChart chart, IEnumerable items, Func converter) + { + if (chart is null) { - return ShowValues(chart, true); + throw new ArgumentNullException(nameof(chart)); } - /// - /// Hides values next to each bar in the bar chart. - /// - /// The bar chart. - /// The same instance so that multiple calls can be chained. - public static BarChart HideValues(this BarChart chart) + if (items is null) { - return ShowValues(chart, false); + throw new ArgumentNullException(nameof(items)); } - /// - /// Sets whether or not values should be shown - /// next to each bar. - /// - /// The bar chart. - /// Whether or not values should be shown next to each bar. - /// The same instance so that multiple calls can be chained. - public static BarChart ShowValues(this BarChart chart, bool show) + if (converter is null) { - if (chart is null) - { - throw new ArgumentNullException(nameof(chart)); - } - - chart.ShowValues = show; - return chart; + throw new ArgumentNullException(nameof(converter)); } - /// - /// Aligns the label to the left. - /// - /// The bar chart. - /// The same instance so that multiple calls can be chained. - public static BarChart LeftAlignLabel(this BarChart chart) + foreach (var item in items) { - if (chart is null) - { - throw new ArgumentNullException(nameof(chart)); - } - - chart.LabelAlignment = Justify.Left; - return chart; + chart.Data.Add(converter(item)); } - /// - /// Centers the label. - /// - /// The bar chart. - /// The same instance so that multiple calls can be chained. - public static BarChart CenterLabel(this BarChart chart) - { - if (chart is null) - { - throw new ArgumentNullException(nameof(chart)); - } + return chart; + } - chart.LabelAlignment = Justify.Center; - return chart; + /// + /// Sets the width of the bar chart. + /// + /// The bar chart. + /// The bar chart width. + /// The same instance so that multiple calls can be chained. + public static BarChart Width(this BarChart chart, int? width) + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); } - /// - /// Aligns the label to the right. - /// - /// The bar chart. - /// The same instance so that multiple calls can be chained. - public static BarChart RightAlignLabel(this BarChart chart) - { - if (chart is null) - { - throw new ArgumentNullException(nameof(chart)); - } + chart.Width = width; + return chart; + } - chart.LabelAlignment = Justify.Right; - return chart; + /// + /// Sets the label of the bar chart. + /// + /// The bar chart. + /// The bar chart label. + /// The same instance so that multiple calls can be chained. + public static BarChart Label(this BarChart chart, string? label) + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); } - /// - /// Sets the max fixed value for the chart. - /// - /// The bar chart. - /// Max value for the chart. - /// The same instance so that multiple calls can be chained. - public static BarChart WithMaxValue(this BarChart chart, double maxValue) - { - if (chart is null) - { - throw new ArgumentNullException(nameof(chart)); - } + chart.Label = label; + return chart; + } - chart.MaxValue = maxValue; - return chart; + /// + /// Shows values next to each bar in the bar chart. + /// + /// The bar chart. + /// The same instance so that multiple calls can be chained. + public static BarChart ShowValues(this BarChart chart) + { + return ShowValues(chart, true); + } + + /// + /// Hides values next to each bar in the bar chart. + /// + /// The bar chart. + /// The same instance so that multiple calls can be chained. + public static BarChart HideValues(this BarChart chart) + { + return ShowValues(chart, false); + } + + /// + /// Sets whether or not values should be shown + /// next to each bar. + /// + /// The bar chart. + /// Whether or not values should be shown next to each bar. + /// The same instance so that multiple calls can be chained. + public static BarChart ShowValues(this BarChart chart, bool show) + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); } + + chart.ShowValues = show; + return chart; + } + + /// + /// Aligns the label to the left. + /// + /// The bar chart. + /// The same instance so that multiple calls can be chained. + public static BarChart LeftAlignLabel(this BarChart chart) + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); + } + + chart.LabelAlignment = Justify.Left; + return chart; + } + + /// + /// Centers the label. + /// + /// The bar chart. + /// The same instance so that multiple calls can be chained. + public static BarChart CenterLabel(this BarChart chart) + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); + } + + chart.LabelAlignment = Justify.Center; + return chart; + } + + /// + /// Aligns the label to the right. + /// + /// The bar chart. + /// The same instance so that multiple calls can be chained. + public static BarChart RightAlignLabel(this BarChart chart) + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); + } + + chart.LabelAlignment = Justify.Right; + return chart; + } + + /// + /// Sets the max fixed value for the chart. + /// + /// The bar chart. + /// Max value for the chart. + /// The same instance so that multiple calls can be chained. + public static BarChart WithMaxValue(this BarChart chart, double maxValue) + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); + } + + chart.MaxValue = maxValue; + return chart; } } \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/BoxExtensions.cs b/src/Spectre.Console/Extensions/BoxExtensions.cs index 9dd5501..fa3871b 100644 --- a/src/Spectre.Console/Extensions/BoxExtensions.cs +++ b/src/Spectre.Console/Extensions/BoxExtensions.cs @@ -1,31 +1,30 @@ using System; -namespace Spectre.Console.Rendering +namespace Spectre.Console.Rendering; + +/// +/// Contains extension methods for . +/// +public static class BoxExtensions { /// - /// Contains extension methods for . + /// Gets the safe border for a border. /// - public static class BoxExtensions + /// The border to get the safe border for. + /// Whether or not to return the safe border. + /// The safe border if one exist, otherwise the original border. + public static BoxBorder GetSafeBorder(this BoxBorder border, bool safe) { - /// - /// Gets the safe border for a border. - /// - /// The border to get the safe border for. - /// Whether or not to return the safe border. - /// The safe border if one exist, otherwise the original border. - public static BoxBorder GetSafeBorder(this BoxBorder border, bool safe) + if (border is null) { - if (border is null) - { - throw new ArgumentNullException(nameof(border)); - } - - if (safe && border.SafeBorder != null) - { - border = border.SafeBorder; - } - - return border; + throw new ArgumentNullException(nameof(border)); } + + if (safe && border.SafeBorder != null) + { + border = border.SafeBorder; + } + + return border; } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/BreakdownChartExtensions.cs b/src/Spectre.Console/Extensions/BreakdownChartExtensions.cs index e19bb43..ffb4efc 100644 --- a/src/Spectre.Console/Extensions/BreakdownChartExtensions.cs +++ b/src/Spectre.Console/Extensions/BreakdownChartExtensions.cs @@ -2,304 +2,303 @@ using System; using System.Collections.Generic; using System.Globalization; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class BreakdownChartExtensions { /// - /// Contains extension methods for . + /// Adds an item to the breakdown chart. /// - public static class BreakdownChartExtensions + /// The breakdown chart. + /// The item label. + /// The item value. + /// The item color. + /// The same instance so that multiple calls can be chained. + public static BreakdownChart AddItem(this BreakdownChart chart, string label, double value, Color color) { - /// - /// Adds an item to the breakdown chart. - /// - /// The breakdown chart. - /// The item label. - /// The item value. - /// The item color. - /// The same instance so that multiple calls can be chained. - public static BreakdownChart AddItem(this BreakdownChart chart, string label, double value, Color color) + if (chart is null) { - if (chart is null) - { - throw new ArgumentNullException(nameof(chart)); - } - - chart.Data.Add(new BreakdownChartItem(label, value, color)); - return chart; + throw new ArgumentNullException(nameof(chart)); } - /// - /// Adds an item to the breakdown chart. - /// - /// A type that implements . - /// The breakdown chart. - /// The item. - /// The same instance so that multiple calls can be chained. - public static BreakdownChart AddItem(this BreakdownChart chart, T item) - where T : IBreakdownChartItem - { - if (chart is null) - { - throw new ArgumentNullException(nameof(chart)); - } - - if (item is BreakdownChartItem chartItem) - { - chart.Data.Add(chartItem); - } - else - { - chart.Data.Add( - new BreakdownChartItem( - item.Label, - item.Value, - item.Color)); - } - - return chart; - } - - /// - /// Adds multiple items to the breakdown chart. - /// - /// A type that implements . - /// The breakdown chart. - /// The items. - /// The same instance so that multiple calls can be chained. - public static BreakdownChart AddItems(this BreakdownChart chart, IEnumerable items) - where T : IBreakdownChartItem - { - if (chart is null) - { - throw new ArgumentNullException(nameof(chart)); - } - - if (items is null) - { - throw new ArgumentNullException(nameof(items)); - } - - foreach (var item in items) - { - AddItem(chart, item); - } - - return chart; - } - - /// - /// Adds multiple items to the breakdown chart. - /// - /// A type that implements . - /// The breakdown chart. - /// The items. - /// The converter that converts instances of T to . - /// The same instance so that multiple calls can be chained. - public static BreakdownChart AddItems(this BreakdownChart chart, IEnumerable items, Func converter) - { - if (chart is null) - { - throw new ArgumentNullException(nameof(chart)); - } - - if (items is null) - { - throw new ArgumentNullException(nameof(items)); - } - - if (converter is null) - { - throw new ArgumentNullException(nameof(converter)); - } - - foreach (var item in items) - { - chart.Data.Add(converter(item)); - } - - return chart; - } - - /// - /// Sets the width of the breakdown chart. - /// - /// The breakdown chart. - /// The breakdown chart width. - /// The same instance so that multiple calls can be chained. - public static BreakdownChart Width(this BreakdownChart chart, int? width) - { - if (chart is null) - { - throw new ArgumentNullException(nameof(chart)); - } - - chart.Width = width; - return chart; - } - - /// - /// Tags will be shown. - /// - /// The breakdown chart. - /// The value formatter to use. - /// The same instance so that multiple calls can be chained. - public static BreakdownChart UseValueFormatter(this BreakdownChart chart, Func? func) - { - if (chart is null) - { - throw new ArgumentNullException(nameof(chart)); - } - - chart.ValueFormatter = func; - return chart; - } - - /// - /// Tags will be shown. - /// - /// The breakdown chart. - /// The value formatter to use. - /// The same instance so that multiple calls can be chained. - public static BreakdownChart UseValueFormatter(this BreakdownChart chart, Func? func) - { - if (chart is null) - { - throw new ArgumentNullException(nameof(chart)); - } - - chart.ValueFormatter = func != null - ? (value, _) => func(value) - : null; - - return chart; - } - - /// - /// Tags will be shown. - /// - /// The breakdown chart. - /// The same instance so that multiple calls can be chained. - public static BreakdownChart ShowPercentage(this BreakdownChart chart) - { - if (chart is null) - { - throw new ArgumentNullException(nameof(chart)); - } - - chart.ValueFormatter = (value, culture) => string.Format(culture, "{0}%", value); - - return chart; - } - - /// - /// Tags will be shown. - /// - /// The breakdown chart. - /// The same instance so that multiple calls can be chained. - public static BreakdownChart ShowTags(this BreakdownChart chart) - { - return ShowTags(chart, true); - } - - /// - /// Tags will be not be shown. - /// - /// The breakdown chart. - /// The same instance so that multiple calls can be chained. - public static BreakdownChart HideTags(this BreakdownChart chart) - { - return ShowTags(chart, false); - } - - /// - /// Sets whether or not tags will be shown. - /// - /// The breakdown chart. - /// Whether or not tags will be shown. - /// The same instance so that multiple calls can be chained. - public static BreakdownChart ShowTags(this BreakdownChart chart, bool show) - { - if (chart is null) - { - throw new ArgumentNullException(nameof(chart)); - } - - chart.ShowTags = show; - return chart; - } - - /// - /// Tag values will be shown. - /// - /// The breakdown chart. - /// The same instance so that multiple calls can be chained. - public static BreakdownChart ShowTagValues(this BreakdownChart chart) - { - return ShowTagValues(chart, true); - } - - /// - /// Tag values will be not be shown. - /// - /// The breakdown chart. - /// The same instance so that multiple calls can be chained. - public static BreakdownChart HideTagValues(this BreakdownChart chart) - { - return ShowTagValues(chart, false); - } - - /// - /// Sets whether or not tag values will be shown. - /// - /// The breakdown chart. - /// Whether or not tag values will be shown. - /// The same instance so that multiple calls can be chained. - public static BreakdownChart ShowTagValues(this BreakdownChart chart, bool show) - { - if (chart is null) - { - throw new ArgumentNullException(nameof(chart)); - } - - chart.ShowTagValues = show; - return chart; - } - - /// - /// Chart and tags is rendered in compact mode. - /// - /// The breakdown chart. - /// The same instance so that multiple calls can be chained. - public static BreakdownChart Compact(this BreakdownChart chart) - { - return Compact(chart, true); - } - - /// - /// Chart and tags is rendered in full size mode. - /// - /// The breakdown chart. - /// The same instance so that multiple calls can be chained. - public static BreakdownChart FullSize(this BreakdownChart chart) - { - return Compact(chart, false); - } - - /// - /// Sets whether or not the chart and tags should be rendered in compact mode. - /// - /// The breakdown chart. - /// Whether or not the chart and tags should be rendered in compact mode. - /// The same instance so that multiple calls can be chained. - public static BreakdownChart Compact(this BreakdownChart chart, bool compact) - { - if (chart is null) - { - throw new ArgumentNullException(nameof(chart)); - } - - chart.Compact = compact; - return chart; - } + chart.Data.Add(new BreakdownChartItem(label, value, color)); + return chart; } -} + + /// + /// Adds an item to the breakdown chart. + /// + /// A type that implements . + /// The breakdown chart. + /// The item. + /// The same instance so that multiple calls can be chained. + public static BreakdownChart AddItem(this BreakdownChart chart, T item) + where T : IBreakdownChartItem + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); + } + + if (item is BreakdownChartItem chartItem) + { + chart.Data.Add(chartItem); + } + else + { + chart.Data.Add( + new BreakdownChartItem( + item.Label, + item.Value, + item.Color)); + } + + return chart; + } + + /// + /// Adds multiple items to the breakdown chart. + /// + /// A type that implements . + /// The breakdown chart. + /// The items. + /// The same instance so that multiple calls can be chained. + public static BreakdownChart AddItems(this BreakdownChart chart, IEnumerable items) + where T : IBreakdownChartItem + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); + } + + if (items is null) + { + throw new ArgumentNullException(nameof(items)); + } + + foreach (var item in items) + { + AddItem(chart, item); + } + + return chart; + } + + /// + /// Adds multiple items to the breakdown chart. + /// + /// A type that implements . + /// The breakdown chart. + /// The items. + /// The converter that converts instances of T to . + /// The same instance so that multiple calls can be chained. + public static BreakdownChart AddItems(this BreakdownChart chart, IEnumerable items, Func converter) + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); + } + + if (items is null) + { + throw new ArgumentNullException(nameof(items)); + } + + if (converter is null) + { + throw new ArgumentNullException(nameof(converter)); + } + + foreach (var item in items) + { + chart.Data.Add(converter(item)); + } + + return chart; + } + + /// + /// Sets the width of the breakdown chart. + /// + /// The breakdown chart. + /// The breakdown chart width. + /// The same instance so that multiple calls can be chained. + public static BreakdownChart Width(this BreakdownChart chart, int? width) + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); + } + + chart.Width = width; + return chart; + } + + /// + /// Tags will be shown. + /// + /// The breakdown chart. + /// The value formatter to use. + /// The same instance so that multiple calls can be chained. + public static BreakdownChart UseValueFormatter(this BreakdownChart chart, Func? func) + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); + } + + chart.ValueFormatter = func; + return chart; + } + + /// + /// Tags will be shown. + /// + /// The breakdown chart. + /// The value formatter to use. + /// The same instance so that multiple calls can be chained. + public static BreakdownChart UseValueFormatter(this BreakdownChart chart, Func? func) + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); + } + + chart.ValueFormatter = func != null + ? (value, _) => func(value) + : null; + + return chart; + } + + /// + /// Tags will be shown. + /// + /// The breakdown chart. + /// The same instance so that multiple calls can be chained. + public static BreakdownChart ShowPercentage(this BreakdownChart chart) + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); + } + + chart.ValueFormatter = (value, culture) => string.Format(culture, "{0}%", value); + + return chart; + } + + /// + /// Tags will be shown. + /// + /// The breakdown chart. + /// The same instance so that multiple calls can be chained. + public static BreakdownChart ShowTags(this BreakdownChart chart) + { + return ShowTags(chart, true); + } + + /// + /// Tags will be not be shown. + /// + /// The breakdown chart. + /// The same instance so that multiple calls can be chained. + public static BreakdownChart HideTags(this BreakdownChart chart) + { + return ShowTags(chart, false); + } + + /// + /// Sets whether or not tags will be shown. + /// + /// The breakdown chart. + /// Whether or not tags will be shown. + /// The same instance so that multiple calls can be chained. + public static BreakdownChart ShowTags(this BreakdownChart chart, bool show) + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); + } + + chart.ShowTags = show; + return chart; + } + + /// + /// Tag values will be shown. + /// + /// The breakdown chart. + /// The same instance so that multiple calls can be chained. + public static BreakdownChart ShowTagValues(this BreakdownChart chart) + { + return ShowTagValues(chart, true); + } + + /// + /// Tag values will be not be shown. + /// + /// The breakdown chart. + /// The same instance so that multiple calls can be chained. + public static BreakdownChart HideTagValues(this BreakdownChart chart) + { + return ShowTagValues(chart, false); + } + + /// + /// Sets whether or not tag values will be shown. + /// + /// The breakdown chart. + /// Whether or not tag values will be shown. + /// The same instance so that multiple calls can be chained. + public static BreakdownChart ShowTagValues(this BreakdownChart chart, bool show) + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); + } + + chart.ShowTagValues = show; + return chart; + } + + /// + /// Chart and tags is rendered in compact mode. + /// + /// The breakdown chart. + /// The same instance so that multiple calls can be chained. + public static BreakdownChart Compact(this BreakdownChart chart) + { + return Compact(chart, true); + } + + /// + /// Chart and tags is rendered in full size mode. + /// + /// The breakdown chart. + /// The same instance so that multiple calls can be chained. + public static BreakdownChart FullSize(this BreakdownChart chart) + { + return Compact(chart, false); + } + + /// + /// Sets whether or not the chart and tags should be rendered in compact mode. + /// + /// The breakdown chart. + /// Whether or not the chart and tags should be rendered in compact mode. + /// The same instance so that multiple calls can be chained. + public static BreakdownChart Compact(this BreakdownChart chart, bool compact) + { + if (chart is null) + { + throw new ArgumentNullException(nameof(chart)); + } + + chart.Compact = compact; + return chart; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/CalendarExtensions.cs b/src/Spectre.Console/Extensions/CalendarExtensions.cs index 0265a89..9c9d119 100644 --- a/src/Spectre.Console/Extensions/CalendarExtensions.cs +++ b/src/Spectre.Console/Extensions/CalendarExtensions.cs @@ -1,132 +1,131 @@ using System; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class CalendarExtensions { /// - /// Contains extension methods for . + /// Adds a calendar event. /// - public static class CalendarExtensions + /// The calendar to add the calendar event to. + /// The calendar event date. + /// The same instance so that multiple calls can be chained. + public static Calendar AddCalendarEvent(this Calendar calendar, DateTime date) { - /// - /// Adds a calendar event. - /// - /// The calendar to add the calendar event to. - /// The calendar event date. - /// The same instance so that multiple calls can be chained. - public static Calendar AddCalendarEvent(this Calendar calendar, DateTime date) - { - return AddCalendarEvent(calendar, string.Empty, date.Year, date.Month, date.Day); - } - - /// - /// Adds a calendar event. - /// - /// The calendar to add the calendar event to. - /// The calendar event description. - /// The calendar event date. - /// The same instance so that multiple calls can be chained. - public static Calendar AddCalendarEvent(this Calendar calendar, string description, DateTime date) - { - return AddCalendarEvent(calendar, description, date.Year, date.Month, date.Day); - } - - /// - /// Adds a calendar event. - /// - /// The calendar to add the calendar event to. - /// The year of the calendar event. - /// The month of the calendar event. - /// The day of the calendar event. - /// The same instance so that multiple calls can be chained. - public static Calendar AddCalendarEvent(this Calendar calendar, int year, int month, int day) - { - return AddCalendarEvent(calendar, string.Empty, year, month, day); - } - - /// - /// Adds a calendar event. - /// - /// The calendar. - /// The calendar event description. - /// The year of the calendar event. - /// The month of the calendar event. - /// The day of the calendar event. - /// The same instance so that multiple calls can be chained. - public static Calendar AddCalendarEvent(this Calendar calendar, string description, int year, int month, int day) - { - if (calendar is null) - { - throw new ArgumentNullException(nameof(calendar)); - } - - calendar.CalendarEvents.Add(new CalendarEvent(description, year, month, day)); - return calendar; - } - - /// - /// Sets the calendar's highlight . - /// - /// The calendar. - /// The highlight style. - /// The same instance so that multiple calls can be chained. - public static Calendar HighlightStyle(this Calendar calendar, Style? style) - { - if (calendar is null) - { - throw new ArgumentNullException(nameof(calendar)); - } - - calendar.HightlightStyle = style ?? Style.Plain; - return calendar; - } - - /// - /// Sets the calendar's header . - /// - /// The calendar. - /// The header style. - /// The same instance so that multiple calls can be chained. - public static Calendar HeaderStyle(this Calendar calendar, Style? style) - { - if (calendar is null) - { - throw new ArgumentNullException(nameof(calendar)); - } - - calendar.HeaderStyle = style ?? Style.Plain; - return calendar; - } - - /// - /// Shows the calendar header. - /// - /// The calendar. - /// The same instance so that multiple calls can be chained. - public static Calendar ShowHeader(this Calendar calendar) - { - if (calendar is null) - { - throw new ArgumentNullException(nameof(calendar)); - } - - calendar.ShowHeader = true; - return calendar; - } - - /// - /// Hides the calendar header. - /// - /// The calendar. - /// The same instance so that multiple calls can be chained. - public static Calendar HideHeader(this Calendar calendar) - { - if (calendar is null) - { - throw new ArgumentNullException(nameof(calendar)); - } - - calendar.ShowHeader = false; - return calendar; - } + return AddCalendarEvent(calendar, string.Empty, date.Year, date.Month, date.Day); } -} + + /// + /// Adds a calendar event. + /// + /// The calendar to add the calendar event to. + /// The calendar event description. + /// The calendar event date. + /// The same instance so that multiple calls can be chained. + public static Calendar AddCalendarEvent(this Calendar calendar, string description, DateTime date) + { + return AddCalendarEvent(calendar, description, date.Year, date.Month, date.Day); + } + + /// + /// Adds a calendar event. + /// + /// The calendar to add the calendar event to. + /// The year of the calendar event. + /// The month of the calendar event. + /// The day of the calendar event. + /// The same instance so that multiple calls can be chained. + public static Calendar AddCalendarEvent(this Calendar calendar, int year, int month, int day) + { + return AddCalendarEvent(calendar, string.Empty, year, month, day); + } + + /// + /// Adds a calendar event. + /// + /// The calendar. + /// The calendar event description. + /// The year of the calendar event. + /// The month of the calendar event. + /// The day of the calendar event. + /// The same instance so that multiple calls can be chained. + public static Calendar AddCalendarEvent(this Calendar calendar, string description, int year, int month, int day) + { + if (calendar is null) + { + throw new ArgumentNullException(nameof(calendar)); + } + + calendar.CalendarEvents.Add(new CalendarEvent(description, year, month, day)); + return calendar; + } + + /// + /// Sets the calendar's highlight . + /// + /// The calendar. + /// The highlight style. + /// The same instance so that multiple calls can be chained. + public static Calendar HighlightStyle(this Calendar calendar, Style? style) + { + if (calendar is null) + { + throw new ArgumentNullException(nameof(calendar)); + } + + calendar.HightlightStyle = style ?? Style.Plain; + return calendar; + } + + /// + /// Sets the calendar's header . + /// + /// The calendar. + /// The header style. + /// The same instance so that multiple calls can be chained. + public static Calendar HeaderStyle(this Calendar calendar, Style? style) + { + if (calendar is null) + { + throw new ArgumentNullException(nameof(calendar)); + } + + calendar.HeaderStyle = style ?? Style.Plain; + return calendar; + } + + /// + /// Shows the calendar header. + /// + /// The calendar. + /// The same instance so that multiple calls can be chained. + public static Calendar ShowHeader(this Calendar calendar) + { + if (calendar is null) + { + throw new ArgumentNullException(nameof(calendar)); + } + + calendar.ShowHeader = true; + return calendar; + } + + /// + /// Hides the calendar header. + /// + /// The calendar. + /// The same instance so that multiple calls can be chained. + public static Calendar HideHeader(this Calendar calendar) + { + if (calendar is null) + { + throw new ArgumentNullException(nameof(calendar)); + } + + calendar.ShowHeader = false; + return calendar; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/CharExtensions.cs b/src/Spectre.Console/Extensions/CharExtensions.cs index 44b7c9f..0b0b3fb 100644 --- a/src/Spectre.Console/Extensions/CharExtensions.cs +++ b/src/Spectre.Console/Extensions/CharExtensions.cs @@ -1,18 +1,17 @@ -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class CharExtensions { /// - /// Contains extension methods for . + /// Gets the cell width of a character. /// - public static class CharExtensions + /// The character to get the cell width of. + /// The cell width of the character. + public static int GetCellWidth(this char character) { - /// - /// Gets the cell width of a character. - /// - /// The character to get the cell width of. - /// The cell width of the character. - public static int GetCellWidth(this char character) - { - return Cell.GetCellLength(character); - } + return Cell.GetCellLength(character); } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/ColumnExtensions.cs b/src/Spectre.Console/Extensions/ColumnExtensions.cs index 3240a85..468ac60 100644 --- a/src/Spectre.Console/Extensions/ColumnExtensions.cs +++ b/src/Spectre.Console/Extensions/ColumnExtensions.cs @@ -1,47 +1,46 @@ using System; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class ColumnExtensions { /// - /// Contains extension methods for . + /// Prevents a column from wrapping. /// - public static class ColumnExtensions + /// An object implementing . + /// The column. + /// The same instance so that multiple calls can be chained. + public static T NoWrap(this T obj) + where T : class, IColumn { - /// - /// Prevents a column from wrapping. - /// - /// An object implementing . - /// The column. - /// The same instance so that multiple calls can be chained. - public static T NoWrap(this T obj) - where T : class, IColumn + if (obj is null) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - obj.NoWrap = true; - return obj; + throw new ArgumentNullException(nameof(obj)); } - /// - /// Sets the width of the column. - /// - /// An object implementing . - /// The column. - /// The column width. - /// The same instance so that multiple calls can be chained. - public static T Width(this T obj, int? width) - where T : class, IColumn - { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - obj.Width = width; - return obj; - } + obj.NoWrap = true; + return obj; } -} + + /// + /// Sets the width of the column. + /// + /// An object implementing . + /// The column. + /// The column width. + /// The same instance so that multiple calls can be chained. + public static T Width(this T obj, int? width) + where T : class, IColumn + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + obj.Width = width; + return obj; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/ConfirmationPromptExtensions.cs b/src/Spectre.Console/Extensions/ConfirmationPromptExtensions.cs index 17c8add..d4196de 100644 --- a/src/Spectre.Console/Extensions/ConfirmationPromptExtensions.cs +++ b/src/Spectre.Console/Extensions/ConfirmationPromptExtensions.cs @@ -1,135 +1,134 @@ using System; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class ConfirmationPromptExtensions { /// - /// Contains extension methods for . + /// Show or hide choices. /// - public static class ConfirmationPromptExtensions + /// The prompt. + /// Whether or not the choices should be visible. + /// The same instance so that multiple calls can be chained. + public static ConfirmationPrompt ShowChoices(this ConfirmationPrompt obj, bool show) { - /// - /// Show or hide choices. - /// - /// The prompt. - /// Whether or not the choices should be visible. - /// The same instance so that multiple calls can be chained. - public static ConfirmationPrompt ShowChoices(this ConfirmationPrompt obj, bool show) + if (obj is null) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - obj.ShowChoices = show; - return obj; + throw new ArgumentNullException(nameof(obj)); } - /// - /// Shows choices. - /// - /// The prompt. - /// The same instance so that multiple calls can be chained. - public static ConfirmationPrompt ShowChoices(this ConfirmationPrompt obj) - { - return ShowChoices(obj, true); - } - - /// - /// Hides choices. - /// - /// The prompt. - /// The same instance so that multiple calls can be chained. - public static ConfirmationPrompt HideChoices(this ConfirmationPrompt obj) - { - return ShowChoices(obj, false); - } - - /// - /// Show or hide the default value. - /// - /// The prompt. - /// Whether or not the default value should be visible. - /// The same instance so that multiple calls can be chained. - public static ConfirmationPrompt ShowDefaultValue(this ConfirmationPrompt obj, bool show) - { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - obj.ShowDefaultValue = show; - return obj; - } - - /// - /// Shows the default value. - /// - /// The prompt. - /// The same instance so that multiple calls can be chained. - public static ConfirmationPrompt ShowDefaultValue(this ConfirmationPrompt obj) - { - return ShowDefaultValue(obj, true); - } - - /// - /// Hides the default value. - /// - /// The prompt. - /// The same instance so that multiple calls can be chained. - public static ConfirmationPrompt HideDefaultValue(this ConfirmationPrompt obj) - { - return ShowDefaultValue(obj, false); - } - - /// - /// Sets the "invalid choice" message for the prompt. - /// - /// The prompt. - /// The "invalid choice" message. - /// The same instance so that multiple calls can be chained. - public static ConfirmationPrompt InvalidChoiceMessage(this ConfirmationPrompt obj, string message) - { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - obj.InvalidChoiceMessage = message; - return obj; - } - - /// - /// Sets the character to interpret as "yes". - /// - /// The confirmation prompt. - /// The character to interpret as "yes". - /// The same instance so that multiple calls can be chained. - public static ConfirmationPrompt Yes(this ConfirmationPrompt obj, char character) - { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - obj.Yes = character; - return obj; - } - - /// - /// Sets the character to interpret as "no". - /// - /// The confirmation prompt. - /// The character to interpret as "no". - /// The same instance so that multiple calls can be chained. - public static ConfirmationPrompt No(this ConfirmationPrompt obj, char character) - { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - obj.No = character; - return obj; - } + obj.ShowChoices = show; + return obj; } -} + + /// + /// Shows choices. + /// + /// The prompt. + /// The same instance so that multiple calls can be chained. + public static ConfirmationPrompt ShowChoices(this ConfirmationPrompt obj) + { + return ShowChoices(obj, true); + } + + /// + /// Hides choices. + /// + /// The prompt. + /// The same instance so that multiple calls can be chained. + public static ConfirmationPrompt HideChoices(this ConfirmationPrompt obj) + { + return ShowChoices(obj, false); + } + + /// + /// Show or hide the default value. + /// + /// The prompt. + /// Whether or not the default value should be visible. + /// The same instance so that multiple calls can be chained. + public static ConfirmationPrompt ShowDefaultValue(this ConfirmationPrompt obj, bool show) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + obj.ShowDefaultValue = show; + return obj; + } + + /// + /// Shows the default value. + /// + /// The prompt. + /// The same instance so that multiple calls can be chained. + public static ConfirmationPrompt ShowDefaultValue(this ConfirmationPrompt obj) + { + return ShowDefaultValue(obj, true); + } + + /// + /// Hides the default value. + /// + /// The prompt. + /// The same instance so that multiple calls can be chained. + public static ConfirmationPrompt HideDefaultValue(this ConfirmationPrompt obj) + { + return ShowDefaultValue(obj, false); + } + + /// + /// Sets the "invalid choice" message for the prompt. + /// + /// The prompt. + /// The "invalid choice" message. + /// The same instance so that multiple calls can be chained. + public static ConfirmationPrompt InvalidChoiceMessage(this ConfirmationPrompt obj, string message) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + obj.InvalidChoiceMessage = message; + return obj; + } + + /// + /// Sets the character to interpret as "yes". + /// + /// The confirmation prompt. + /// The character to interpret as "yes". + /// The same instance so that multiple calls can be chained. + public static ConfirmationPrompt Yes(this ConfirmationPrompt obj, char character) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + obj.Yes = character; + return obj; + } + + /// + /// Sets the character to interpret as "no". + /// + /// The confirmation prompt. + /// The character to interpret as "no". + /// The same instance so that multiple calls can be chained. + public static ConfirmationPrompt No(this ConfirmationPrompt obj, char character) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + obj.No = character; + return obj; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/CursorExtensions.cs b/src/Spectre.Console/Extensions/CursorExtensions.cs index 57cd8b8..f7eb159 100644 --- a/src/Spectre.Console/Extensions/CursorExtensions.cs +++ b/src/Spectre.Console/Extensions/CursorExtensions.cs @@ -1,152 +1,151 @@ -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class CursorExtensions { /// - /// Contains extension methods for . + /// Shows the cursor. /// - public static class CursorExtensions + /// The cursor. + public static void Show(this IAnsiConsoleCursor cursor) { - /// - /// Shows the cursor. - /// - /// The cursor. - public static void Show(this IAnsiConsoleCursor cursor) + if (cursor is null) { - if (cursor is null) - { - throw new System.ArgumentNullException(nameof(cursor)); - } - - cursor.Show(true); + throw new System.ArgumentNullException(nameof(cursor)); } - /// - /// Hides the cursor. - /// - /// The cursor. - public static void Hide(this IAnsiConsoleCursor cursor) - { - if (cursor is null) - { - throw new System.ArgumentNullException(nameof(cursor)); - } - - cursor.Show(false); - } - - /// - /// Moves the cursor up. - /// - /// The cursor. - public static void MoveUp(this IAnsiConsoleCursor cursor) - { - if (cursor is null) - { - throw new System.ArgumentNullException(nameof(cursor)); - } - - cursor.Move(CursorDirection.Up, 1); - } - - /// - /// Moves the cursor up. - /// - /// The cursor. - /// The number of steps to move the cursor. - public static void MoveUp(this IAnsiConsoleCursor cursor, int steps) - { - if (cursor is null) - { - throw new System.ArgumentNullException(nameof(cursor)); - } - - cursor.Move(CursorDirection.Up, steps); - } - - /// - /// Moves the cursor down. - /// - /// The cursor. - public static void MoveDown(this IAnsiConsoleCursor cursor) - { - if (cursor is null) - { - throw new System.ArgumentNullException(nameof(cursor)); - } - - cursor.Move(CursorDirection.Down, 1); - } - - /// - /// Moves the cursor down. - /// - /// The cursor. - /// The number of steps to move the cursor. - public static void MoveDown(this IAnsiConsoleCursor cursor, int steps) - { - if (cursor is null) - { - throw new System.ArgumentNullException(nameof(cursor)); - } - - cursor.Move(CursorDirection.Down, steps); - } - - /// - /// Moves the cursor to the left. - /// - /// The cursor. - public static void MoveLeft(this IAnsiConsoleCursor cursor) - { - if (cursor is null) - { - throw new System.ArgumentNullException(nameof(cursor)); - } - - cursor.Move(CursorDirection.Left, 1); - } - - /// - /// Moves the cursor to the left. - /// - /// The cursor. - /// The number of steps to move the cursor. - public static void MoveLeft(this IAnsiConsoleCursor cursor, int steps) - { - if (cursor is null) - { - throw new System.ArgumentNullException(nameof(cursor)); - } - - cursor.Move(CursorDirection.Left, steps); - } - - /// - /// Moves the cursor to the right. - /// - /// The cursor. - public static void MoveRight(this IAnsiConsoleCursor cursor) - { - if (cursor is null) - { - throw new System.ArgumentNullException(nameof(cursor)); - } - - cursor.Move(CursorDirection.Right, 1); - } - - /// - /// Moves the cursor to the right. - /// - /// The cursor. - /// The number of steps to move the cursor. - public static void MoveRight(this IAnsiConsoleCursor cursor, int steps) - { - if (cursor is null) - { - throw new System.ArgumentNullException(nameof(cursor)); - } - - cursor.Move(CursorDirection.Right, steps); - } + cursor.Show(true); } -} + + /// + /// Hides the cursor. + /// + /// The cursor. + public static void Hide(this IAnsiConsoleCursor cursor) + { + if (cursor is null) + { + throw new System.ArgumentNullException(nameof(cursor)); + } + + cursor.Show(false); + } + + /// + /// Moves the cursor up. + /// + /// The cursor. + public static void MoveUp(this IAnsiConsoleCursor cursor) + { + if (cursor is null) + { + throw new System.ArgumentNullException(nameof(cursor)); + } + + cursor.Move(CursorDirection.Up, 1); + } + + /// + /// Moves the cursor up. + /// + /// The cursor. + /// The number of steps to move the cursor. + public static void MoveUp(this IAnsiConsoleCursor cursor, int steps) + { + if (cursor is null) + { + throw new System.ArgumentNullException(nameof(cursor)); + } + + cursor.Move(CursorDirection.Up, steps); + } + + /// + /// Moves the cursor down. + /// + /// The cursor. + public static void MoveDown(this IAnsiConsoleCursor cursor) + { + if (cursor is null) + { + throw new System.ArgumentNullException(nameof(cursor)); + } + + cursor.Move(CursorDirection.Down, 1); + } + + /// + /// Moves the cursor down. + /// + /// The cursor. + /// The number of steps to move the cursor. + public static void MoveDown(this IAnsiConsoleCursor cursor, int steps) + { + if (cursor is null) + { + throw new System.ArgumentNullException(nameof(cursor)); + } + + cursor.Move(CursorDirection.Down, steps); + } + + /// + /// Moves the cursor to the left. + /// + /// The cursor. + public static void MoveLeft(this IAnsiConsoleCursor cursor) + { + if (cursor is null) + { + throw new System.ArgumentNullException(nameof(cursor)); + } + + cursor.Move(CursorDirection.Left, 1); + } + + /// + /// Moves the cursor to the left. + /// + /// The cursor. + /// The number of steps to move the cursor. + public static void MoveLeft(this IAnsiConsoleCursor cursor, int steps) + { + if (cursor is null) + { + throw new System.ArgumentNullException(nameof(cursor)); + } + + cursor.Move(CursorDirection.Left, steps); + } + + /// + /// Moves the cursor to the right. + /// + /// The cursor. + public static void MoveRight(this IAnsiConsoleCursor cursor) + { + if (cursor is null) + { + throw new System.ArgumentNullException(nameof(cursor)); + } + + cursor.Move(CursorDirection.Right, 1); + } + + /// + /// Moves the cursor to the right. + /// + /// The cursor. + /// The number of steps to move the cursor. + public static void MoveRight(this IAnsiConsoleCursor cursor, int steps) + { + if (cursor is null) + { + throw new System.ArgumentNullException(nameof(cursor)); + } + + cursor.Move(CursorDirection.Right, steps); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/DayOfWeekExtensions.cs b/src/Spectre.Console/Extensions/DayOfWeekExtensions.cs index 557d81d..11377bc 100644 --- a/src/Spectre.Console/Extensions/DayOfWeekExtensions.cs +++ b/src/Spectre.Console/Extensions/DayOfWeekExtensions.cs @@ -1,27 +1,26 @@ using System; using System.Globalization; -namespace Spectre.Console +namespace Spectre.Console; + +internal static class DayOfWeekExtensions { - internal static class DayOfWeekExtensions + public static string GetAbbreviatedDayName(this DayOfWeek day, CultureInfo culture) { - public static string GetAbbreviatedDayName(this DayOfWeek day, CultureInfo culture) - { - culture ??= CultureInfo.InvariantCulture; - return culture.DateTimeFormat - .GetAbbreviatedDayName(day) - .CapitalizeFirstLetter(culture); - } - - public static DayOfWeek GetNextWeekDay(this DayOfWeek day) - { - var next = (int)day + 1; - if (next > (int)DayOfWeek.Saturday) - { - return DayOfWeek.Sunday; - } - - return (DayOfWeek)next; - } + culture ??= CultureInfo.InvariantCulture; + return culture.DateTimeFormat + .GetAbbreviatedDayName(day) + .CapitalizeFirstLetter(culture); } -} + + public static DayOfWeek GetNextWeekDay(this DayOfWeek day) + { + var next = (int)day + 1; + if (next > (int)DayOfWeek.Saturday) + { + return DayOfWeek.Sunday; + } + + return (DayOfWeek)next; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/DictionaryExtensions.cs b/src/Spectre.Console/Extensions/DictionaryExtensions.cs index fdba057..4f87502 100644 --- a/src/Spectre.Console/Extensions/DictionaryExtensions.cs +++ b/src/Spectre.Console/Extensions/DictionaryExtensions.cs @@ -1,13 +1,12 @@ using System.Collections.Generic; -namespace Spectre.Console +namespace Spectre.Console; + +internal static class DictionaryExtensions { - internal static class DictionaryExtensions + public static void Deconstruct(this KeyValuePair tuple, out T1 key, out T2 value) { - public static void Deconstruct(this KeyValuePair tuple, out T1 key, out T2 value) - { - key = tuple.Key; - value = tuple.Value; - } + key = tuple.Key; + value = tuple.Value; } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/EnumerableExtensions.cs b/src/Spectre.Console/Extensions/EnumerableExtensions.cs index 3dec660..2eb8442 100644 --- a/src/Spectre.Console/Extensions/EnumerableExtensions.cs +++ b/src/Spectre.Console/Extensions/EnumerableExtensions.cs @@ -2,131 +2,130 @@ using System; using System.Collections.Generic; using System.Linq; -namespace Spectre.Console +namespace Spectre.Console; + +internal static class EnumerableExtensions { - internal static class EnumerableExtensions + // List.Reverse clashes with IEnumerable.Reverse, so this method only exists + // so we won't have to cast List to IEnumerable. + public static IEnumerable ReverseEnumerable(this IEnumerable source) { - // List.Reverse clashes with IEnumerable.Reverse, so this method only exists - // so we won't have to cast List to IEnumerable. - public static IEnumerable ReverseEnumerable(this IEnumerable source) + if (source is null) { - if (source is null) - { - throw new ArgumentNullException(nameof(source)); - } - - return source.Reverse(); + throw new ArgumentNullException(nameof(source)); } - public static bool None(this IEnumerable source, Func predicate) - { - return !source.Any(predicate); - } + return source.Reverse(); + } - public static IEnumerable Repeat(this IEnumerable source, int count) - { - while (count-- > 0) - { - foreach (var item in source) - { - yield return item; - } - } - } + public static bool None(this IEnumerable source, Func predicate) + { + return !source.Any(predicate); + } - public static int IndexOf(this IEnumerable source, T item) - where T : class - { - var index = 0; - foreach (var candidate in source) - { - if (candidate == item) - { - return index; - } - - index++; - } - - return -1; - } - - public static int GetCount(this IEnumerable source) - { - if (source is IList list) - { - return list.Count; - } - - if (source is T[] array) - { - return array.Length; - } - - return source.Count(); - } - - public static void ForEach(this IEnumerable source, Action action) + public static IEnumerable Repeat(this IEnumerable source, int count) + { + while (count-- > 0) { foreach (var item in source) { - action(item); + yield return item; } } - - public static bool AnyTrue(this IEnumerable source) - { - return source.Any(b => b); - } - - public static IEnumerable<(int Index, bool First, bool Last, T Item)> Enumerate(this IEnumerable source) - { - if (source is null) - { - throw new ArgumentNullException(nameof(source)); - } - - return Enumerate(source.GetEnumerator()); - } - - public static IEnumerable<(int Index, bool First, bool Last, T Item)> Enumerate(this IEnumerator source) - { - if (source is null) - { - throw new ArgumentNullException(nameof(source)); - } - - var first = true; - var last = !source.MoveNext(); - T current; - - for (var index = 0; !last; index++) - { - current = source.Current; - last = !source.MoveNext(); - yield return (index, first, last, current); - first = false; - } - } - - public static IEnumerable SelectIndex(this IEnumerable source, Func func) - { - return source.Select((value, index) => func(value, index)); - } - -#if !NET5_0 - public static IEnumerable<(TFirst First, TSecond Second)> Zip( - this IEnumerable source, IEnumerable first) - { - return source.Zip(first, (first, second) => (first, second)); - } -#endif - - public static IEnumerable<(TFirst First, TSecond Second, TThird Third)> Zip( - this IEnumerable first, IEnumerable second, IEnumerable third) - { - return first.Zip(second, (a, b) => (a, b)) - .Zip(third, (a, b) => (a.a, a.b, b)); - } } -} + + public static int IndexOf(this IEnumerable source, T item) + where T : class + { + var index = 0; + foreach (var candidate in source) + { + if (candidate == item) + { + return index; + } + + index++; + } + + return -1; + } + + public static int GetCount(this IEnumerable source) + { + if (source is IList list) + { + return list.Count; + } + + if (source is T[] array) + { + return array.Length; + } + + return source.Count(); + } + + public static void ForEach(this IEnumerable source, Action action) + { + foreach (var item in source) + { + action(item); + } + } + + public static bool AnyTrue(this IEnumerable source) + { + return source.Any(b => b); + } + + public static IEnumerable<(int Index, bool First, bool Last, T Item)> Enumerate(this IEnumerable source) + { + if (source is null) + { + throw new ArgumentNullException(nameof(source)); + } + + return Enumerate(source.GetEnumerator()); + } + + public static IEnumerable<(int Index, bool First, bool Last, T Item)> Enumerate(this IEnumerator source) + { + if (source is null) + { + throw new ArgumentNullException(nameof(source)); + } + + var first = true; + var last = !source.MoveNext(); + T current; + + for (var index = 0; !last; index++) + { + current = source.Current; + last = !source.MoveNext(); + yield return (index, first, last, current); + first = false; + } + } + + public static IEnumerable SelectIndex(this IEnumerable source, Func func) + { + return source.Select((value, index) => func(value, index)); + } + +#if !NET5_0_OR_GREATER + public static IEnumerable<(TFirst First, TSecond Second)> Zip( + this IEnumerable source, IEnumerable first) + { + return source.Zip(first, (first, second) => (first, second)); + } +#endif + + public static IEnumerable<(TFirst First, TSecond Second, TThird Third)> Zip( + this IEnumerable first, IEnumerable second, IEnumerable third) + { + return first.Zip(second, (a, b) => (a, b)) + .Zip(third, (a, b) => (a.a, a.b, b)); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/ExceptionExtensions.cs b/src/Spectre.Console/Extensions/ExceptionExtensions.cs index aa0c0aa..1977061 100644 --- a/src/Spectre.Console/Extensions/ExceptionExtensions.cs +++ b/src/Spectre.Console/Extensions/ExceptionExtensions.cs @@ -1,51 +1,50 @@ using System; using Spectre.Console.Rendering; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class ExceptionExtensions { /// - /// Contains extension methods for . + /// Gets a representation of the exception. /// - public static class ExceptionExtensions + /// The exception to format. + /// The exception format options. + /// A representing the exception. + public static IRenderable GetRenderable(this Exception exception, ExceptionFormats format = ExceptionFormats.Default) { - /// - /// Gets a representation of the exception. - /// - /// The exception to format. - /// The exception format options. - /// A representing the exception. - public static IRenderable GetRenderable(this Exception exception, ExceptionFormats format = ExceptionFormats.Default) + if (exception is null) { - if (exception is null) - { - throw new ArgumentNullException(nameof(exception)); - } - - return GetRenderable(exception, new ExceptionSettings - { - Format = format, - }); + throw new ArgumentNullException(nameof(exception)); } - /// - /// Gets a representation of the exception. - /// - /// The exception to format. - /// The exception settings. - /// A representing the exception. - public static IRenderable GetRenderable(this Exception exception, ExceptionSettings settings) + return GetRenderable(exception, new ExceptionSettings { - if (exception is null) - { - throw new ArgumentNullException(nameof(exception)); - } - - if (settings is null) - { - throw new ArgumentNullException(nameof(settings)); - } - - return ExceptionFormatter.Format(exception, settings); - } + Format = format, + }); } -} + + /// + /// Gets a representation of the exception. + /// + /// The exception to format. + /// The exception settings. + /// A representing the exception. + public static IRenderable GetRenderable(this Exception exception, ExceptionSettings settings) + { + if (exception is null) + { + throw new ArgumentNullException(nameof(exception)); + } + + if (settings is null) + { + throw new ArgumentNullException(nameof(settings)); + } + + return ExceptionFormatter.Format(exception, settings); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/ExpandableExtensions.cs b/src/Spectre.Console/Extensions/ExpandableExtensions.cs index 723d58a..18acf8c 100644 --- a/src/Spectre.Console/Extensions/ExpandableExtensions.cs +++ b/src/Spectre.Console/Extensions/ExpandableExtensions.cs @@ -1,47 +1,46 @@ using System; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class ExpandableExtensions { /// - /// Contains extension methods for . + /// Tells the specified object to not expand to the available area + /// but take as little space as possible. /// - public static class ExpandableExtensions + /// The expandable object. + /// The object to collapse. + /// The same instance so that multiple calls can be chained. + public static T Collapse(this T obj) + where T : class, IExpandable { - /// - /// Tells the specified object to not expand to the available area - /// but take as little space as possible. - /// - /// The expandable object. - /// The object to collapse. - /// The same instance so that multiple calls can be chained. - public static T Collapse(this T obj) - where T : class, IExpandable + if (obj is null) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - obj.Expand = false; - return obj; + throw new ArgumentNullException(nameof(obj)); } - /// - /// Tells the specified object to expand to the available area. - /// - /// The expandable object. - /// The object to expand. - /// The same instance so that multiple calls can be chained. - public static T Expand(this T obj) - where T : class, IExpandable - { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - obj.Expand = true; - return obj; - } + obj.Expand = false; + return obj; } -} + + /// + /// Tells the specified object to expand to the available area. + /// + /// The expandable object. + /// The object to expand. + /// The same instance so that multiple calls can be chained. + public static T Expand(this T obj) + where T : class, IExpandable + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + obj.Expand = true; + return obj; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/FigletTextExtensions.cs b/src/Spectre.Console/Extensions/FigletTextExtensions.cs index 7457653..f6b4375 100644 --- a/src/Spectre.Console/Extensions/FigletTextExtensions.cs +++ b/src/Spectre.Console/Extensions/FigletTextExtensions.cs @@ -1,27 +1,26 @@ using System; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class FigletTextExtensions { /// - /// Contains extension methods for . + /// Sets the color of the FIGlet text. /// - public static class FigletTextExtensions + /// The text. + /// The color. + /// The same instance so that multiple calls can be chained. + public static FigletText Color(this FigletText text, Color? color) { - /// - /// Sets the color of the FIGlet text. - /// - /// The text. - /// The color. - /// The same instance so that multiple calls can be chained. - public static FigletText Color(this FigletText text, Color? color) + if (text is null) { - if (text is null) - { - throw new ArgumentNullException(nameof(text)); - } - - text.Color = color ?? Console.Color.Default; - return text; + throw new ArgumentNullException(nameof(text)); } + + text.Color = color ?? Console.Color.Default; + return text; } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/GridExtensions.cs b/src/Spectre.Console/Extensions/GridExtensions.cs index fbd3bb1..494677d 100644 --- a/src/Spectre.Console/Extensions/GridExtensions.cs +++ b/src/Spectre.Console/Extensions/GridExtensions.cs @@ -2,116 +2,115 @@ using System; using System.Linq; using Spectre.Console.Rendering; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class GridExtensions { /// - /// Contains extension methods for . + /// Adds a column to the grid. /// - public static class GridExtensions + /// The grid to add the column to. + /// The number of columns to add. + /// The same instance so that multiple calls can be chained. + public static Grid AddColumns(this Grid grid, int count) { - /// - /// Adds a column to the grid. - /// - /// The grid to add the column to. - /// The number of columns to add. - /// The same instance so that multiple calls can be chained. - public static Grid AddColumns(this Grid grid, int count) + if (grid is null) { - if (grid is null) - { - throw new ArgumentNullException(nameof(grid)); - } - - for (var index = 0; index < count; index++) - { - grid.AddColumn(new GridColumn()); - } - - return grid; + throw new ArgumentNullException(nameof(grid)); } - /// - /// Adds a column to the grid. - /// - /// The grid to add the column to. - /// The columns to add. - /// The same instance so that multiple calls can be chained. - public static Grid AddColumns(this Grid grid, params GridColumn[] columns) + for (var index = 0; index < count; index++) { - if (grid is null) - { - throw new ArgumentNullException(nameof(grid)); - } - - if (columns is null) - { - throw new ArgumentNullException(nameof(columns)); - } - - foreach (var column in columns) - { - grid.AddColumn(column); - } - - return grid; + grid.AddColumn(new GridColumn()); } - /// - /// Adds an empty row to the grid. - /// - /// The grid to add the row to. - /// The same instance so that multiple calls can be chained. - public static Grid AddEmptyRow(this Grid grid) - { - if (grid is null) - { - throw new ArgumentNullException(nameof(grid)); - } - - var columns = new IRenderable[grid.Columns.Count]; - Enumerable.Range(0, grid.Columns.Count).ForEach(index => columns[index] = Text.Empty); - grid.AddRow(columns); - - return grid; - } - - /// - /// Adds a new row to the grid. - /// - /// The grid to add the row to. - /// The columns to add. - /// The same instance so that multiple calls can be chained. - public static Grid AddRow(this Grid grid, params string[] columns) - { - if (grid is null) - { - throw new ArgumentNullException(nameof(grid)); - } - - if (columns is null) - { - throw new ArgumentNullException(nameof(columns)); - } - - grid.AddRow(columns.Select(column => new Markup(column)).ToArray()); - return grid; - } - - /// - /// Sets the grid width. - /// - /// The grid. - /// The width. - /// The same instance so that multiple calls can be chained. - public static Grid Width(this Grid grid, int? width) - { - if (grid is null) - { - throw new ArgumentNullException(nameof(grid)); - } - - grid.Width = width; - return grid; - } + return grid; } -} + + /// + /// Adds a column to the grid. + /// + /// The grid to add the column to. + /// The columns to add. + /// The same instance so that multiple calls can be chained. + public static Grid AddColumns(this Grid grid, params GridColumn[] columns) + { + if (grid is null) + { + throw new ArgumentNullException(nameof(grid)); + } + + if (columns is null) + { + throw new ArgumentNullException(nameof(columns)); + } + + foreach (var column in columns) + { + grid.AddColumn(column); + } + + return grid; + } + + /// + /// Adds an empty row to the grid. + /// + /// The grid to add the row to. + /// The same instance so that multiple calls can be chained. + public static Grid AddEmptyRow(this Grid grid) + { + if (grid is null) + { + throw new ArgumentNullException(nameof(grid)); + } + + var columns = new IRenderable[grid.Columns.Count]; + Enumerable.Range(0, grid.Columns.Count).ForEach(index => columns[index] = Text.Empty); + grid.AddRow(columns); + + return grid; + } + + /// + /// Adds a new row to the grid. + /// + /// The grid to add the row to. + /// The columns to add. + /// The same instance so that multiple calls can be chained. + public static Grid AddRow(this Grid grid, params string[] columns) + { + if (grid is null) + { + throw new ArgumentNullException(nameof(grid)); + } + + if (columns is null) + { + throw new ArgumentNullException(nameof(columns)); + } + + grid.AddRow(columns.Select(column => new Markup(column)).ToArray()); + return grid; + } + + /// + /// Sets the grid width. + /// + /// The grid. + /// The width. + /// The same instance so that multiple calls can be chained. + public static Grid Width(this Grid grid, int? width) + { + if (grid is null) + { + throw new ArgumentNullException(nameof(grid)); + } + + grid.Width = width; + return grid; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/HasBorderExtensions.cs b/src/Spectre.Console/Extensions/HasBorderExtensions.cs index ad64a75..1ebed1d 100644 --- a/src/Spectre.Console/Extensions/HasBorderExtensions.cs +++ b/src/Spectre.Console/Extensions/HasBorderExtensions.cs @@ -1,84 +1,83 @@ using System; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class HasBorderExtensions { /// - /// Contains extension methods for . + /// Enables the safe border. /// - public static class HasBorderExtensions + /// An object type with a border. + /// The object to enable the safe border for. + /// The same instance so that multiple calls can be chained. + public static T SafeBorder(this T obj) + where T : class, IHasBorder { - /// - /// Enables the safe border. - /// - /// An object type with a border. - /// The object to enable the safe border for. - /// The same instance so that multiple calls can be chained. - public static T SafeBorder(this T obj) - where T : class, IHasBorder + if (obj is null) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - obj.UseSafeBorder = true; - return obj; + throw new ArgumentNullException(nameof(obj)); } - /// - /// Disables the safe border. - /// - /// An object type with a border. - /// The object to disable the safe border for. - /// The same instance so that multiple calls can be chained. - public static T NoSafeBorder(this T obj) - where T : class, IHasBorder - { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - obj.UseSafeBorder = false; - return obj; - } - - /// - /// Sets the border style. - /// - /// An object type with a border. - /// The object to set the border style for. - /// The border style to set. - /// The same instance so that multiple calls can be chained. - public static T BorderStyle(this T obj, Style style) - where T : class, IHasBorder - { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - obj.BorderStyle = style; - return obj; - } - - /// - /// Sets the border color. - /// - /// An object type with a border. - /// The object to set the border color for. - /// The border color to set. - /// The same instance so that multiple calls can be chained. - public static T BorderColor(this T obj, Color color) - where T : class, IHasBorder - { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - obj.BorderStyle = (obj.BorderStyle ?? Style.Plain).Foreground(color); - return obj; - } + obj.UseSafeBorder = true; + return obj; } -} + + /// + /// Disables the safe border. + /// + /// An object type with a border. + /// The object to disable the safe border for. + /// The same instance so that multiple calls can be chained. + public static T NoSafeBorder(this T obj) + where T : class, IHasBorder + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + obj.UseSafeBorder = false; + return obj; + } + + /// + /// Sets the border style. + /// + /// An object type with a border. + /// The object to set the border style for. + /// The border style to set. + /// The same instance so that multiple calls can be chained. + public static T BorderStyle(this T obj, Style style) + where T : class, IHasBorder + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + obj.BorderStyle = style; + return obj; + } + + /// + /// Sets the border color. + /// + /// An object type with a border. + /// The object to set the border color for. + /// The border color to set. + /// The same instance so that multiple calls can be chained. + public static T BorderColor(this T obj, Color color) + where T : class, IHasBorder + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + obj.BorderStyle = (obj.BorderStyle ?? Style.Plain).Foreground(color); + return obj; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/HasBoxBorderExtensions.cs b/src/Spectre.Console/Extensions/HasBoxBorderExtensions.cs index 5378d87..3d7354e 100644 --- a/src/Spectre.Console/Extensions/HasBoxBorderExtensions.cs +++ b/src/Spectre.Console/Extensions/HasBoxBorderExtensions.cs @@ -1,101 +1,100 @@ using System; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class HasBoxBorderExtensions { /// - /// Contains extension methods for . + /// Sets the border. /// - public static class HasBoxBorderExtensions + /// An object type with a border. + /// The object to set the border for. + /// The border to use. + /// The same instance so that multiple calls can be chained. + public static T Border(this T obj, BoxBorder border) + where T : class, IHasBoxBorder { - /// - /// Sets the border. - /// - /// An object type with a border. - /// The object to set the border for. - /// The border to use. - /// The same instance so that multiple calls can be chained. - public static T Border(this T obj, BoxBorder border) - where T : class, IHasBoxBorder + if (obj is null) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - obj.Border = border; - return obj; + throw new ArgumentNullException(nameof(obj)); } - /// - /// Do not display a border. - /// - /// An object type with a border. - /// The object to set the border for. - /// The same instance so that multiple calls can be chained. - public static T NoBorder(this T obj) - where T : class, IHasBoxBorder - { - return Border(obj, BoxBorder.None); - } - - /// - /// Display a square border. - /// - /// An object type with a border. - /// The object to set the border for. - /// The same instance so that multiple calls can be chained. - public static T SquareBorder(this T obj) - where T : class, IHasBoxBorder - { - return Border(obj, BoxBorder.Square); - } - - /// - /// Display an ASCII border. - /// - /// An object type with a border. - /// The object to set the border for. - /// The same instance so that multiple calls can be chained. - public static T AsciiBorder(this T obj) - where T : class, IHasBoxBorder - { - return Border(obj, BoxBorder.Ascii); - } - - /// - /// Display a rounded border. - /// - /// An object type with a border. - /// The object to set the border for. - /// The same instance so that multiple calls can be chained. - public static T RoundedBorder(this T obj) - where T : class, IHasBoxBorder - { - return Border(obj, BoxBorder.Rounded); - } - - /// - /// Display a heavy border. - /// - /// An object type with a border. - /// The object to set the border for. - /// The same instance so that multiple calls can be chained. - public static T HeavyBorder(this T obj) - where T : class, IHasBoxBorder - { - return Border(obj, BoxBorder.Heavy); - } - - /// - /// Display a double border. - /// - /// An object type with a border. - /// The object to set the border for. - /// The same instance so that multiple calls can be chained. - public static T DoubleBorder(this T obj) - where T : class, IHasBoxBorder - { - return Border(obj, BoxBorder.Double); - } + obj.Border = border; + return obj; } -} + + /// + /// Do not display a border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T NoBorder(this T obj) + where T : class, IHasBoxBorder + { + return Border(obj, BoxBorder.None); + } + + /// + /// Display a square border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T SquareBorder(this T obj) + where T : class, IHasBoxBorder + { + return Border(obj, BoxBorder.Square); + } + + /// + /// Display an ASCII border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T AsciiBorder(this T obj) + where T : class, IHasBoxBorder + { + return Border(obj, BoxBorder.Ascii); + } + + /// + /// Display a rounded border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T RoundedBorder(this T obj) + where T : class, IHasBoxBorder + { + return Border(obj, BoxBorder.Rounded); + } + + /// + /// Display a heavy border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T HeavyBorder(this T obj) + where T : class, IHasBoxBorder + { + return Border(obj, BoxBorder.Heavy); + } + + /// + /// Display a double border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T DoubleBorder(this T obj) + where T : class, IHasBoxBorder + { + return Border(obj, BoxBorder.Double); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/HasCultureExtensions.cs b/src/Spectre.Console/Extensions/HasCultureExtensions.cs index 27ed4a0..53e7911 100644 --- a/src/Spectre.Console/Extensions/HasCultureExtensions.cs +++ b/src/Spectre.Console/Extensions/HasCultureExtensions.cs @@ -1,66 +1,65 @@ using System; using System.Globalization; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class HasCultureExtensions { /// - /// Contains extension methods for . + /// Sets the culture. /// - public static class HasCultureExtensions + /// An object type with a culture. + /// The object to set the culture for. + /// The culture to set. + /// The same instance so that multiple calls can be chained. + public static T Culture(this T obj, CultureInfo culture) + where T : class, IHasCulture { - /// - /// Sets the culture. - /// - /// An object type with a culture. - /// The object to set the culture for. - /// The culture to set. - /// The same instance so that multiple calls can be chained. - public static T Culture(this T obj, CultureInfo culture) - where T : class, IHasCulture + if (obj is null) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - if (culture is null) - { - throw new ArgumentNullException(nameof(culture)); - } - - obj.Culture = culture; - return obj; + throw new ArgumentNullException(nameof(obj)); } - /// - /// Sets the culture. - /// - /// An object type with a culture. - /// The object to set the culture for. - /// The culture to set. - /// The same instance so that multiple calls can be chained. - public static T Culture(this T obj, string name) - where T : class, IHasCulture + if (culture is null) { - if (name is null) - { - throw new ArgumentNullException(nameof(name)); - } - - return Culture(obj, CultureInfo.GetCultureInfo(name)); + throw new ArgumentNullException(nameof(culture)); } - /// - /// Sets the culture. - /// - /// An object type with a culture. - /// The object to set the culture for. - /// The culture to set. - /// The same instance so that multiple calls can be chained. - public static T Culture(this T obj, int culture) - where T : class, IHasCulture - { - return Culture(obj, CultureInfo.GetCultureInfo(culture)); - } + obj.Culture = culture; + return obj; } -} + + /// + /// Sets the culture. + /// + /// An object type with a culture. + /// The object to set the culture for. + /// The culture to set. + /// The same instance so that multiple calls can be chained. + public static T Culture(this T obj, string name) + where T : class, IHasCulture + { + if (name is null) + { + throw new ArgumentNullException(nameof(name)); + } + + return Culture(obj, CultureInfo.GetCultureInfo(name)); + } + + /// + /// Sets the culture. + /// + /// An object type with a culture. + /// The object to set the culture for. + /// The culture to set. + /// The same instance so that multiple calls can be chained. + public static T Culture(this T obj, int culture) + where T : class, IHasCulture + { + return Culture(obj, CultureInfo.GetCultureInfo(culture)); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/HasTableBorderExtensions.cs b/src/Spectre.Console/Extensions/HasTableBorderExtensions.cs index 52cbadc..3aba4ad 100644 --- a/src/Spectre.Console/Extensions/HasTableBorderExtensions.cs +++ b/src/Spectre.Console/Extensions/HasTableBorderExtensions.cs @@ -1,245 +1,244 @@ using System; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class HasTableBorderExtensions { /// - /// Contains extension methods for . + /// Do not display a border. /// - public static class HasTableBorderExtensions + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T NoBorder(this T obj) + where T : class, IHasTableBorder { - /// - /// Do not display a border. - /// - /// An object type with a border. - /// The object to set the border for. - /// The same instance so that multiple calls can be chained. - public static T NoBorder(this T obj) - where T : class, IHasTableBorder - { - return Border(obj, TableBorder.None); - } - - /// - /// Display a square border. - /// - /// An object type with a border. - /// The object to set the border for. - /// The same instance so that multiple calls can be chained. - public static T SquareBorder(this T obj) - where T : class, IHasTableBorder - { - return Border(obj, TableBorder.Square); - } - - /// - /// Display an ASCII border. - /// - /// An object type with a border. - /// The object to set the border for. - /// The same instance so that multiple calls can be chained. - public static T AsciiBorder(this T obj) - where T : class, IHasTableBorder - { - return Border(obj, TableBorder.Ascii); - } - - /// - /// Display another ASCII border. - /// - /// An object type with a border. - /// The object to set the border for. - /// The same instance so that multiple calls can be chained. - public static T Ascii2Border(this T obj) - where T : class, IHasTableBorder - { - return Border(obj, TableBorder.Ascii2); - } - - /// - /// Display an ASCII border with a double header border. - /// - /// An object type with a border. - /// The object to set the border for. - /// The same instance so that multiple calls can be chained. - public static T AsciiDoubleHeadBorder(this T obj) - where T : class, IHasTableBorder - { - return Border(obj, TableBorder.AsciiDoubleHead); - } - - /// - /// Display a rounded border. - /// - /// An object type with a border. - /// The object to set the border for. - /// The same instance so that multiple calls can be chained. - public static T RoundedBorder(this T obj) - where T : class, IHasTableBorder - { - return Border(obj, TableBorder.Rounded); - } - - /// - /// Display a minimal border. - /// - /// An object type with a border. - /// The object to set the border for. - /// The same instance so that multiple calls can be chained. - public static T MinimalBorder(this T obj) - where T : class, IHasTableBorder - { - return Border(obj, TableBorder.Minimal); - } - - /// - /// Display a minimal border with a heavy head. - /// - /// An object type with a border. - /// The object to set the border for. - /// The same instance so that multiple calls can be chained. - public static T MinimalHeavyHeadBorder(this T obj) - where T : class, IHasTableBorder - { - return Border(obj, TableBorder.MinimalHeavyHead); - } - - /// - /// Display a minimal border with a double header border. - /// - /// An object type with a border. - /// The object to set the border for. - /// The same instance so that multiple calls can be chained. - public static T MinimalDoubleHeadBorder(this T obj) - where T : class, IHasTableBorder - { - return Border(obj, TableBorder.MinimalDoubleHead); - } - - /// - /// Display a simple border. - /// - /// An object type with a border. - /// The object to set the border for. - /// The same instance so that multiple calls can be chained. - public static T SimpleBorder(this T obj) - where T : class, IHasTableBorder - { - return Border(obj, TableBorder.Simple); - } - - /// - /// Display a simple border with heavy lines. - /// - /// An object type with a border. - /// The object to set the border for. - /// The same instance so that multiple calls can be chained. - public static T SimpleHeavyBorder(this T obj) - where T : class, IHasTableBorder - { - return Border(obj, TableBorder.SimpleHeavy); - } - - /// - /// Display a simple border. - /// - /// An object type with a border. - /// The object to set the border for. - /// The same instance so that multiple calls can be chained. - public static T HorizontalBorder(this T obj) - where T : class, IHasTableBorder - { - return Border(obj, TableBorder.Horizontal); - } - - /// - /// Display a heavy border. - /// - /// An object type with a border. - /// The object to set the border for. - /// The same instance so that multiple calls can be chained. - public static T HeavyBorder(this T obj) - where T : class, IHasTableBorder - { - return Border(obj, TableBorder.Heavy); - } - - /// - /// Display a border with a heavy edge. - /// - /// An object type with a border. - /// The object to set the border for. - /// The same instance so that multiple calls can be chained. - public static T HeavyEdgeBorder(this T obj) - where T : class, IHasTableBorder - { - return Border(obj, TableBorder.HeavyEdge); - } - - /// - /// Display a border with a heavy header. - /// - /// An object type with a border. - /// The object to set the border for. - /// The same instance so that multiple calls can be chained. - public static T HeavyHeadBorder(this T obj) - where T : class, IHasTableBorder - { - return Border(obj, TableBorder.HeavyHead); - } - - /// - /// Display a double border. - /// - /// An object type with a border. - /// The object to set the border for. - /// The same instance so that multiple calls can be chained. - public static T DoubleBorder(this T obj) - where T : class, IHasTableBorder - { - return Border(obj, TableBorder.Double); - } - - /// - /// Display a border with a double edge. - /// - /// An object type with a border. - /// The object to set the border for. - /// The same instance so that multiple calls can be chained. - public static T DoubleEdgeBorder(this T obj) - where T : class, IHasTableBorder - { - return Border(obj, TableBorder.DoubleEdge); - } - - /// - /// Display a markdown border. - /// - /// An object type with a border. - /// The object to set the border for. - /// The same instance so that multiple calls can be chained. - public static T MarkdownBorder(this T obj) - where T : class, IHasTableBorder - { - return Border(obj, TableBorder.Markdown); - } - - /// - /// Sets the border. - /// - /// An object type with a border. - /// The object to set the border for. - /// The border to use. - /// The same instance so that multiple calls can be chained. - public static T Border(this T obj, TableBorder border) - where T : class, IHasTableBorder - { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - obj.Border = border; - return obj; - } + return Border(obj, TableBorder.None); } -} + + /// + /// Display a square border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T SquareBorder(this T obj) + where T : class, IHasTableBorder + { + return Border(obj, TableBorder.Square); + } + + /// + /// Display an ASCII border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T AsciiBorder(this T obj) + where T : class, IHasTableBorder + { + return Border(obj, TableBorder.Ascii); + } + + /// + /// Display another ASCII border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T Ascii2Border(this T obj) + where T : class, IHasTableBorder + { + return Border(obj, TableBorder.Ascii2); + } + + /// + /// Display an ASCII border with a double header border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T AsciiDoubleHeadBorder(this T obj) + where T : class, IHasTableBorder + { + return Border(obj, TableBorder.AsciiDoubleHead); + } + + /// + /// Display a rounded border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T RoundedBorder(this T obj) + where T : class, IHasTableBorder + { + return Border(obj, TableBorder.Rounded); + } + + /// + /// Display a minimal border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T MinimalBorder(this T obj) + where T : class, IHasTableBorder + { + return Border(obj, TableBorder.Minimal); + } + + /// + /// Display a minimal border with a heavy head. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T MinimalHeavyHeadBorder(this T obj) + where T : class, IHasTableBorder + { + return Border(obj, TableBorder.MinimalHeavyHead); + } + + /// + /// Display a minimal border with a double header border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T MinimalDoubleHeadBorder(this T obj) + where T : class, IHasTableBorder + { + return Border(obj, TableBorder.MinimalDoubleHead); + } + + /// + /// Display a simple border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T SimpleBorder(this T obj) + where T : class, IHasTableBorder + { + return Border(obj, TableBorder.Simple); + } + + /// + /// Display a simple border with heavy lines. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T SimpleHeavyBorder(this T obj) + where T : class, IHasTableBorder + { + return Border(obj, TableBorder.SimpleHeavy); + } + + /// + /// Display a simple border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T HorizontalBorder(this T obj) + where T : class, IHasTableBorder + { + return Border(obj, TableBorder.Horizontal); + } + + /// + /// Display a heavy border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T HeavyBorder(this T obj) + where T : class, IHasTableBorder + { + return Border(obj, TableBorder.Heavy); + } + + /// + /// Display a border with a heavy edge. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T HeavyEdgeBorder(this T obj) + where T : class, IHasTableBorder + { + return Border(obj, TableBorder.HeavyEdge); + } + + /// + /// Display a border with a heavy header. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T HeavyHeadBorder(this T obj) + where T : class, IHasTableBorder + { + return Border(obj, TableBorder.HeavyHead); + } + + /// + /// Display a double border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T DoubleBorder(this T obj) + where T : class, IHasTableBorder + { + return Border(obj, TableBorder.Double); + } + + /// + /// Display a border with a double edge. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T DoubleEdgeBorder(this T obj) + where T : class, IHasTableBorder + { + return Border(obj, TableBorder.DoubleEdge); + } + + /// + /// Display a markdown border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The same instance so that multiple calls can be chained. + public static T MarkdownBorder(this T obj) + where T : class, IHasTableBorder + { + return Border(obj, TableBorder.Markdown); + } + + /// + /// Sets the border. + /// + /// An object type with a border. + /// The object to set the border for. + /// The border to use. + /// The same instance so that multiple calls can be chained. + public static T Border(this T obj, TableBorder border) + where T : class, IHasTableBorder + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + obj.Border = border; + return obj; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/HasTreeNodeExtensions.cs b/src/Spectre.Console/Extensions/HasTreeNodeExtensions.cs index 0417c2f..7a8bbd0 100644 --- a/src/Spectre.Console/Extensions/HasTreeNodeExtensions.cs +++ b/src/Spectre.Console/Extensions/HasTreeNodeExtensions.cs @@ -3,215 +3,214 @@ using System.Collections.Generic; using System.Linq; using Spectre.Console.Rendering; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class HasTreeNodeExtensions { /// - /// Contains extension methods for . + /// Adds a tree node. /// - public static class HasTreeNodeExtensions + /// An object with tree nodes. + /// The object to add the tree node to. + /// The node's markup text. + /// The added tree node. + public static TreeNode AddNode(this T obj, string markup) + where T : IHasTreeNodes { - /// - /// Adds a tree node. - /// - /// An object with tree nodes. - /// The object to add the tree node to. - /// The node's markup text. - /// The added tree node. - public static TreeNode AddNode(this T obj, string markup) - where T : IHasTreeNodes + if (obj is null) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - if (markup is null) - { - throw new ArgumentNullException(nameof(markup)); - } - - return AddNode(obj, new Markup(markup)); + throw new ArgumentNullException(nameof(obj)); } - /// - /// Adds a tree node. - /// - /// An object with tree nodes. - /// The object to add the tree node to. - /// The renderable to add. - /// The added tree node. - public static TreeNode AddNode(this T obj, IRenderable renderable) - where T : IHasTreeNodes + if (markup is null) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - if (renderable is null) - { - throw new ArgumentNullException(nameof(renderable)); - } - - var node = new TreeNode(renderable); - obj.Nodes.Add(node); - return node; + throw new ArgumentNullException(nameof(markup)); } - /// - /// Adds a tree node. - /// - /// An object with tree nodes. - /// The object to add the tree node to. - /// The tree node to add. - /// The added tree node. - public static TreeNode AddNode(this T obj, TreeNode node) - where T : IHasTreeNodes - { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - if (node is null) - { - throw new ArgumentNullException(nameof(node)); - } - - obj.Nodes.Add(node); - return node; - } - - /// - /// Add multiple tree nodes. - /// - /// An object with tree nodes. - /// The object to add the tree nodes to. - /// The tree nodes to add. - public static void AddNodes(this T obj, params string[] nodes) - where T : IHasTreeNodes - { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - if (nodes is null) - { - throw new ArgumentNullException(nameof(nodes)); - } - - obj.Nodes.AddRange(nodes.Select(node => new TreeNode(new Markup(node)))); - } - - /// - /// Add multiple tree nodes. - /// - /// An object with tree nodes. - /// The object to add the tree nodes to. - /// The tree nodes to add. - public static void AddNodes(this T obj, IEnumerable nodes) - where T : IHasTreeNodes - { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - if (nodes is null) - { - throw new ArgumentNullException(nameof(nodes)); - } - - obj.Nodes.AddRange(nodes.Select(node => new TreeNode(new Markup(node)))); - } - - /// - /// Add multiple tree nodes. - /// - /// An object with tree nodes. - /// The object to add the tree nodes to. - /// The tree nodes to add. - public static void AddNodes(this T obj, params IRenderable[] nodes) - where T : IHasTreeNodes - { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - if (nodes is null) - { - throw new ArgumentNullException(nameof(nodes)); - } - - obj.Nodes.AddRange(nodes.Select(node => new TreeNode(node))); - } - - /// - /// Add multiple tree nodes. - /// - /// An object with tree nodes. - /// The object to add the tree nodes to. - /// The tree nodes to add. - public static void AddNodes(this T obj, IEnumerable nodes) - where T : IHasTreeNodes - { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - if (nodes is null) - { - throw new ArgumentNullException(nameof(nodes)); - } - - obj.Nodes.AddRange(nodes.Select(node => new TreeNode(node))); - } - - /// - /// Add multiple tree nodes. - /// - /// An object with tree nodes. - /// The object to add the tree nodes to. - /// The tree nodes to add. - public static void AddNodes(this T obj, params TreeNode[] nodes) - where T : IHasTreeNodes - { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - if (nodes is null) - { - throw new ArgumentNullException(nameof(nodes)); - } - - obj.Nodes.AddRange(nodes); - } - - /// - /// Add multiple tree nodes. - /// - /// An object with tree nodes. - /// The object to add the tree nodes to. - /// The tree nodes to add. - public static void AddNodes(this T obj, IEnumerable nodes) - where T : IHasTreeNodes - { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - if (nodes is null) - { - throw new ArgumentNullException(nameof(nodes)); - } - - obj.Nodes.AddRange(nodes); - } + return AddNode(obj, new Markup(markup)); } -} + + /// + /// Adds a tree node. + /// + /// An object with tree nodes. + /// The object to add the tree node to. + /// The renderable to add. + /// The added tree node. + public static TreeNode AddNode(this T obj, IRenderable renderable) + where T : IHasTreeNodes + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + if (renderable is null) + { + throw new ArgumentNullException(nameof(renderable)); + } + + var node = new TreeNode(renderable); + obj.Nodes.Add(node); + return node; + } + + /// + /// Adds a tree node. + /// + /// An object with tree nodes. + /// The object to add the tree node to. + /// The tree node to add. + /// The added tree node. + public static TreeNode AddNode(this T obj, TreeNode node) + where T : IHasTreeNodes + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + if (node is null) + { + throw new ArgumentNullException(nameof(node)); + } + + obj.Nodes.Add(node); + return node; + } + + /// + /// Add multiple tree nodes. + /// + /// An object with tree nodes. + /// The object to add the tree nodes to. + /// The tree nodes to add. + public static void AddNodes(this T obj, params string[] nodes) + where T : IHasTreeNodes + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + if (nodes is null) + { + throw new ArgumentNullException(nameof(nodes)); + } + + obj.Nodes.AddRange(nodes.Select(node => new TreeNode(new Markup(node)))); + } + + /// + /// Add multiple tree nodes. + /// + /// An object with tree nodes. + /// The object to add the tree nodes to. + /// The tree nodes to add. + public static void AddNodes(this T obj, IEnumerable nodes) + where T : IHasTreeNodes + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + if (nodes is null) + { + throw new ArgumentNullException(nameof(nodes)); + } + + obj.Nodes.AddRange(nodes.Select(node => new TreeNode(new Markup(node)))); + } + + /// + /// Add multiple tree nodes. + /// + /// An object with tree nodes. + /// The object to add the tree nodes to. + /// The tree nodes to add. + public static void AddNodes(this T obj, params IRenderable[] nodes) + where T : IHasTreeNodes + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + if (nodes is null) + { + throw new ArgumentNullException(nameof(nodes)); + } + + obj.Nodes.AddRange(nodes.Select(node => new TreeNode(node))); + } + + /// + /// Add multiple tree nodes. + /// + /// An object with tree nodes. + /// The object to add the tree nodes to. + /// The tree nodes to add. + public static void AddNodes(this T obj, IEnumerable nodes) + where T : IHasTreeNodes + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + if (nodes is null) + { + throw new ArgumentNullException(nameof(nodes)); + } + + obj.Nodes.AddRange(nodes.Select(node => new TreeNode(node))); + } + + /// + /// Add multiple tree nodes. + /// + /// An object with tree nodes. + /// The object to add the tree nodes to. + /// The tree nodes to add. + public static void AddNodes(this T obj, params TreeNode[] nodes) + where T : IHasTreeNodes + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + if (nodes is null) + { + throw new ArgumentNullException(nameof(nodes)); + } + + obj.Nodes.AddRange(nodes); + } + + /// + /// Add multiple tree nodes. + /// + /// An object with tree nodes. + /// The object to add the tree nodes to. + /// The tree nodes to add. + public static void AddNodes(this T obj, IEnumerable nodes) + where T : IHasTreeNodes + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + if (nodes is null) + { + throw new ArgumentNullException(nameof(nodes)); + } + + obj.Nodes.AddRange(nodes); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/Int32Extensions.cs b/src/Spectre.Console/Extensions/Int32Extensions.cs index a9f6c32..8ef25a8 100644 --- a/src/Spectre.Console/Extensions/Int32Extensions.cs +++ b/src/Spectre.Console/Extensions/Int32Extensions.cs @@ -1,20 +1,19 @@ -namespace Spectre.Console +namespace Spectre.Console; + +internal static class Int32Extensions { - internal static class Int32Extensions + public static int Clamp(this int value, int min, int max) { - public static int Clamp(this int value, int min, int max) + if (value <= min) { - if (value <= min) - { - return min; - } - - if (value >= max) - { - return max; - } - - return value; + return min; } + + if (value >= max) + { + return max; + } + + return value; } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/ListExtensions.cs b/src/Spectre.Console/Extensions/ListExtensions.cs index ecc66d2..87d7252 100644 --- a/src/Spectre.Console/Extensions/ListExtensions.cs +++ b/src/Spectre.Console/Extensions/ListExtensions.cs @@ -1,38 +1,37 @@ using System; using System.Collections.Generic; -namespace Spectre.Console -{ - internal static class ListExtensions - { - public static void RemoveLast(this List list) - { - if (list is null) - { - throw new ArgumentNullException(nameof(list)); - } +namespace Spectre.Console; - if (list.Count > 0) - { - list.RemoveAt(list.Count - 1); - } +internal static class ListExtensions +{ + public static void RemoveLast(this List list) + { + if (list is null) + { + throw new ArgumentNullException(nameof(list)); } - public static void AddOrReplaceLast(this List list, T item) + if (list.Count > 0) { - if (list is null) - { - throw new ArgumentNullException(nameof(list)); - } - - if (list.Count == 0) - { - list.Add(item); - } - else - { - list[list.Count - 1] = item; - } + list.RemoveAt(list.Count - 1); } } -} + + public static void AddOrReplaceLast(this List list, T item) + { + if (list is null) + { + throw new ArgumentNullException(nameof(list)); + } + + if (list.Count == 0) + { + list.Add(item); + } + else + { + list[list.Count - 1] = item; + } + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/LiveDisplayExtensions.cs b/src/Spectre.Console/Extensions/LiveDisplayExtensions.cs index a5087c3..69c02e8 100644 --- a/src/Spectre.Console/Extensions/LiveDisplayExtensions.cs +++ b/src/Spectre.Console/Extensions/LiveDisplayExtensions.cs @@ -1,65 +1,64 @@ using System; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class LiveDisplayExtensions { /// - /// Contains extension methods for . + /// Sets whether or not auto clear is enabled. + /// If enabled, the live display will be cleared when done. /// - public static class LiveDisplayExtensions + /// The instance. + /// Whether or not auto clear is enabled. + /// The same instance so that multiple calls can be chained. + public static LiveDisplay AutoClear(this LiveDisplay live, bool enabled) { - /// - /// Sets whether or not auto clear is enabled. - /// If enabled, the live display will be cleared when done. - /// - /// The instance. - /// Whether or not auto clear is enabled. - /// The same instance so that multiple calls can be chained. - public static LiveDisplay AutoClear(this LiveDisplay live, bool enabled) + if (live is null) { - if (live is null) - { - throw new ArgumentNullException(nameof(live)); - } - - live.AutoClear = enabled; - - return live; + throw new ArgumentNullException(nameof(live)); } - /// - /// Sets the vertical overflow strategy. - /// - /// The instance. - /// The overflow strategy to use. - /// The same instance so that multiple calls can be chained. - public static LiveDisplay Overflow(this LiveDisplay live, VerticalOverflow overflow) - { - if (live is null) - { - throw new ArgumentNullException(nameof(live)); - } + live.AutoClear = enabled; - live.Overflow = overflow; - - return live; - } - - /// - /// Sets the vertical overflow cropping strategy. - /// - /// The instance. - /// The overflow cropping strategy to use. - /// The same instance so that multiple calls can be chained. - public static LiveDisplay Cropping(this LiveDisplay live, VerticalOverflowCropping cropping) - { - if (live is null) - { - throw new ArgumentNullException(nameof(live)); - } - - live.Cropping = cropping; - - return live; - } + return live; } -} + + /// + /// Sets the vertical overflow strategy. + /// + /// The instance. + /// The overflow strategy to use. + /// The same instance so that multiple calls can be chained. + public static LiveDisplay Overflow(this LiveDisplay live, VerticalOverflow overflow) + { + if (live is null) + { + throw new ArgumentNullException(nameof(live)); + } + + live.Overflow = overflow; + + return live; + } + + /// + /// Sets the vertical overflow cropping strategy. + /// + /// The instance. + /// The overflow cropping strategy to use. + /// The same instance so that multiple calls can be chained. + public static LiveDisplay Cropping(this LiveDisplay live, VerticalOverflowCropping cropping) + { + if (live is null) + { + throw new ArgumentNullException(nameof(live)); + } + + live.Cropping = cropping; + + return live; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/OverflowableExtensions.cs b/src/Spectre.Console/Extensions/OverflowableExtensions.cs index c55966a..0fe33be 100644 --- a/src/Spectre.Console/Extensions/OverflowableExtensions.cs +++ b/src/Spectre.Console/Extensions/OverflowableExtensions.cs @@ -1,80 +1,79 @@ using System; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class OverflowableExtensions { /// - /// Contains extension methods for . + /// Folds any overflowing text. /// - public static class OverflowableExtensions + /// An object implementing . + /// The overflowable object instance. + /// The same instance so that multiple calls can be chained. + public static T Fold(this T obj) + where T : class, IOverflowable { - /// - /// Folds any overflowing text. - /// - /// An object implementing . - /// The overflowable object instance. - /// The same instance so that multiple calls can be chained. - public static T Fold(this T obj) - where T : class, IOverflowable + if (obj is null) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - return Overflow(obj, Console.Overflow.Fold); + throw new ArgumentNullException(nameof(obj)); } - /// - /// Crops any overflowing text. - /// - /// An object implementing . - /// The overflowable object instance. - /// The same instance so that multiple calls can be chained. - public static T Crop(this T obj) - where T : class, IOverflowable - { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - return Overflow(obj, Console.Overflow.Crop); - } - - /// - /// Crops any overflowing text and adds an ellipsis to the end. - /// - /// An object implementing . - /// The overflowable object instance. - /// The same instance so that multiple calls can be chained. - public static T Ellipsis(this T obj) - where T : class, IOverflowable - { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - return Overflow(obj, Console.Overflow.Ellipsis); - } - - /// - /// Sets the overflow strategy. - /// - /// An object implementing . - /// The overflowable object instance. - /// The overflow strategy to use. - /// The same instance so that multiple calls can be chained. - public static T Overflow(this T obj, Overflow overflow) - where T : class, IOverflowable - { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - obj.Overflow = overflow; - return obj; - } + return Overflow(obj, Console.Overflow.Fold); } -} + + /// + /// Crops any overflowing text. + /// + /// An object implementing . + /// The overflowable object instance. + /// The same instance so that multiple calls can be chained. + public static T Crop(this T obj) + where T : class, IOverflowable + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + return Overflow(obj, Console.Overflow.Crop); + } + + /// + /// Crops any overflowing text and adds an ellipsis to the end. + /// + /// An object implementing . + /// The overflowable object instance. + /// The same instance so that multiple calls can be chained. + public static T Ellipsis(this T obj) + where T : class, IOverflowable + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + return Overflow(obj, Console.Overflow.Ellipsis); + } + + /// + /// Sets the overflow strategy. + /// + /// An object implementing . + /// The overflowable object instance. + /// The overflow strategy to use. + /// The same instance so that multiple calls can be chained. + public static T Overflow(this T obj, Overflow overflow) + where T : class, IOverflowable + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + obj.Overflow = overflow; + return obj; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/PaddableExtensions.cs b/src/Spectre.Console/Extensions/PaddableExtensions.cs index ca03847..6ee787c 100644 --- a/src/Spectre.Console/Extensions/PaddableExtensions.cs +++ b/src/Spectre.Console/Extensions/PaddableExtensions.cs @@ -1,131 +1,130 @@ using System; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class PaddableExtensions { /// - /// Contains extension methods for . + /// Sets the left padding. /// - public static class PaddableExtensions + /// An object implementing . + /// The paddable object instance. + /// The left padding. + /// The same instance so that multiple calls can be chained. + public static T PadLeft(this T obj, int left) + where T : class, IPaddable { - /// - /// Sets the left padding. - /// - /// An object implementing . - /// The paddable object instance. - /// The left padding. - /// The same instance so that multiple calls can be chained. - public static T PadLeft(this T obj, int left) - where T : class, IPaddable + if (obj is null) { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - return Padding(obj, new Padding(left, obj.Padding.GetTopSafe(), obj.Padding.GetRightSafe(), obj.Padding.GetBottomSafe())); + throw new ArgumentNullException(nameof(obj)); } - /// - /// Sets the top padding. - /// - /// An object implementing . - /// The paddable object instance. - /// The top padding. - /// The same instance so that multiple calls can be chained. - public static T PadTop(this T obj, int top) - where T : class, IPaddable - { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - return Padding(obj, new Padding(obj.Padding.GetLeftSafe(), top, obj.Padding.GetRightSafe(), obj.Padding.GetBottomSafe())); - } - - /// - /// Sets the right padding. - /// - /// An object implementing . - /// The paddable object instance. - /// The right padding. - /// The same instance so that multiple calls can be chained. - public static T PadRight(this T obj, int right) - where T : class, IPaddable - { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - return Padding(obj, new Padding(obj.Padding.GetLeftSafe(), obj.Padding.GetTopSafe(), right, obj.Padding.GetBottomSafe())); - } - - /// - /// Sets the bottom padding. - /// - /// An object implementing . - /// The paddable object instance. - /// The bottom padding. - /// The same instance so that multiple calls can be chained. - public static T PadBottom(this T obj, int bottom) - where T : class, IPaddable - { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - return Padding(obj, new Padding(obj.Padding.GetLeftSafe(), obj.Padding.GetTopSafe(), obj.Padding.GetRightSafe(), bottom)); - } - - /// - /// Sets the left, top, right and bottom padding. - /// - /// An object implementing . - /// The paddable object instance. - /// The left padding to apply. - /// The top padding to apply. - /// The right padding to apply. - /// The bottom padding to apply. - /// The same instance so that multiple calls can be chained. - public static T Padding(this T obj, int left, int top, int right, int bottom) - where T : class, IPaddable - { - return Padding(obj, new Padding(left, top, right, bottom)); - } - - /// - /// Sets the horizontal and vertical padding. - /// - /// An object implementing . - /// The paddable object instance. - /// The left and right padding. - /// The top and bottom padding. - /// The same instance so that multiple calls can be chained. - public static T Padding(this T obj, int horizontal, int vertical) - where T : class, IPaddable - { - return Padding(obj, new Padding(horizontal, vertical)); - } - - /// - /// Sets the padding. - /// - /// An object implementing . - /// The paddable object instance. - /// The padding to apply. - /// The same instance so that multiple calls can be chained. - public static T Padding(this T obj, Padding padding) - where T : class, IPaddable - { - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } - - obj.Padding = padding; - return obj; - } + return Padding(obj, new Padding(left, obj.Padding.GetTopSafe(), obj.Padding.GetRightSafe(), obj.Padding.GetBottomSafe())); } -} + + /// + /// Sets the top padding. + /// + /// An object implementing . + /// The paddable object instance. + /// The top padding. + /// The same instance so that multiple calls can be chained. + public static T PadTop(this T obj, int top) + where T : class, IPaddable + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + return Padding(obj, new Padding(obj.Padding.GetLeftSafe(), top, obj.Padding.GetRightSafe(), obj.Padding.GetBottomSafe())); + } + + /// + /// Sets the right padding. + /// + /// An object implementing . + /// The paddable object instance. + /// The right padding. + /// The same instance so that multiple calls can be chained. + public static T PadRight(this T obj, int right) + where T : class, IPaddable + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + return Padding(obj, new Padding(obj.Padding.GetLeftSafe(), obj.Padding.GetTopSafe(), right, obj.Padding.GetBottomSafe())); + } + + /// + /// Sets the bottom padding. + /// + /// An object implementing . + /// The paddable object instance. + /// The bottom padding. + /// The same instance so that multiple calls can be chained. + public static T PadBottom(this T obj, int bottom) + where T : class, IPaddable + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + return Padding(obj, new Padding(obj.Padding.GetLeftSafe(), obj.Padding.GetTopSafe(), obj.Padding.GetRightSafe(), bottom)); + } + + /// + /// Sets the left, top, right and bottom padding. + /// + /// An object implementing . + /// The paddable object instance. + /// The left padding to apply. + /// The top padding to apply. + /// The right padding to apply. + /// The bottom padding to apply. + /// The same instance so that multiple calls can be chained. + public static T Padding(this T obj, int left, int top, int right, int bottom) + where T : class, IPaddable + { + return Padding(obj, new Padding(left, top, right, bottom)); + } + + /// + /// Sets the horizontal and vertical padding. + /// + /// An object implementing . + /// The paddable object instance. + /// The left and right padding. + /// The top and bottom padding. + /// The same instance so that multiple calls can be chained. + public static T Padding(this T obj, int horizontal, int vertical) + where T : class, IPaddable + { + return Padding(obj, new Padding(horizontal, vertical)); + } + + /// + /// Sets the padding. + /// + /// An object implementing . + /// The paddable object instance. + /// The padding to apply. + /// The same instance so that multiple calls can be chained. + public static T Padding(this T obj, Padding padding) + where T : class, IPaddable + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + obj.Padding = padding; + return obj; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/PaddingExtensions.cs b/src/Spectre.Console/Extensions/PaddingExtensions.cs index beccd8e..9949092 100644 --- a/src/Spectre.Console/Extensions/PaddingExtensions.cs +++ b/src/Spectre.Console/Extensions/PaddingExtensions.cs @@ -1,48 +1,47 @@ -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class PaddingExtensions { /// - /// Contains extension methods for . + /// Gets the left padding. /// - public static class PaddingExtensions + /// The padding. + /// The left padding or zero if padding is null. + public static int GetLeftSafe(this Padding? padding) { - /// - /// Gets the left padding. - /// - /// The padding. - /// The left padding or zero if padding is null. - public static int GetLeftSafe(this Padding? padding) - { - return padding?.Left ?? 0; - } - - /// - /// Gets the right padding. - /// - /// The padding. - /// The right padding or zero if padding is null. - public static int GetRightSafe(this Padding? padding) - { - return padding?.Right ?? 0; - } - - /// - /// Gets the top padding. - /// - /// The padding. - /// The top padding or zero if padding is null. - public static int GetTopSafe(this Padding? padding) - { - return padding?.Top ?? 0; - } - - /// - /// Gets the bottom padding. - /// - /// The padding. - /// The bottom padding or zero if padding is null. - public static int GetBottomSafe(this Padding? padding) - { - return padding?.Bottom ?? 0; - } + return padding?.Left ?? 0; } -} + + /// + /// Gets the right padding. + /// + /// The padding. + /// The right padding or zero if padding is null. + public static int GetRightSafe(this Padding? padding) + { + return padding?.Right ?? 0; + } + + /// + /// Gets the top padding. + /// + /// The padding. + /// The top padding or zero if padding is null. + public static int GetTopSafe(this Padding? padding) + { + return padding?.Top ?? 0; + } + + /// + /// Gets the bottom padding. + /// + /// The padding. + /// The bottom padding or zero if padding is null. + public static int GetBottomSafe(this Padding? padding) + { + return padding?.Bottom ?? 0; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/PanelExtensions.cs b/src/Spectre.Console/Extensions/PanelExtensions.cs index 9505fe5..7475bfc 100644 --- a/src/Spectre.Console/Extensions/PanelExtensions.cs +++ b/src/Spectre.Console/Extensions/PanelExtensions.cs @@ -1,77 +1,76 @@ using System; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class PanelExtensions { /// - /// Contains extension methods for . + /// Sets the panel header. /// - public static class PanelExtensions + /// The panel. + /// The header text. + /// The header alignment. + /// The same instance so that multiple calls can be chained. + public static Panel Header(this Panel panel, string text, Justify? alignment = null) { - /// - /// Sets the panel header. - /// - /// The panel. - /// The header text. - /// The header alignment. - /// The same instance so that multiple calls can be chained. - public static Panel Header(this Panel panel, string text, Justify? alignment = null) + if (panel is null) { - if (panel is null) - { - throw new ArgumentNullException(nameof(panel)); - } - - if (text is null) - { - throw new ArgumentNullException(nameof(text)); - } - - alignment ??= panel.Header?.Alignment; - return Header(panel, new PanelHeader(text, alignment)); + throw new ArgumentNullException(nameof(panel)); } - /// - /// Sets the panel header alignment. - /// - /// The panel. - /// The header alignment. - /// The same instance so that multiple calls can be chained. - public static Panel HeaderAlignment(this Panel panel, Justify alignment) + if (text is null) { - if (panel is null) - { - throw new ArgumentNullException(nameof(panel)); - } - - if (panel.Header != null) - { - // Update existing style - panel.Header.Alignment = alignment; - } - else - { - // Create header - Header(panel, string.Empty, alignment); - } - - return panel; + throw new ArgumentNullException(nameof(text)); } - /// - /// Sets the panel header. - /// - /// The panel. - /// The header to use. - /// The same instance so that multiple calls can be chained. - public static Panel Header(this Panel panel, PanelHeader header) - { - if (panel is null) - { - throw new ArgumentNullException(nameof(panel)); - } - - panel.Header = header; - return panel; - } + alignment ??= panel.Header?.Alignment; + return Header(panel, new PanelHeader(text, alignment)); } -} + + /// + /// Sets the panel header alignment. + /// + /// The panel. + /// The header alignment. + /// The same instance so that multiple calls can be chained. + public static Panel HeaderAlignment(this Panel panel, Justify alignment) + { + if (panel is null) + { + throw new ArgumentNullException(nameof(panel)); + } + + if (panel.Header != null) + { + // Update existing style + panel.Header.Alignment = alignment; + } + else + { + // Create header + Header(panel, string.Empty, alignment); + } + + return panel; + } + + /// + /// Sets the panel header. + /// + /// The panel. + /// The header to use. + /// The same instance so that multiple calls can be chained. + public static Panel Header(this Panel panel, PanelHeader header) + { + if (panel is null) + { + throw new ArgumentNullException(nameof(panel)); + } + + panel.Header = header; + return panel; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/Progress/PercentageColumnExtensions.cs b/src/Spectre.Console/Extensions/Progress/PercentageColumnExtensions.cs index 9d68752..eae9e11 100644 --- a/src/Spectre.Console/Extensions/Progress/PercentageColumnExtensions.cs +++ b/src/Spectre.Console/Extensions/Progress/PercentageColumnExtensions.cs @@ -1,54 +1,53 @@ using System; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class PercentageColumnExtensions { /// - /// Contains extension methods for . + /// Sets the style for a non-complete task. /// - public static class PercentageColumnExtensions + /// The column. + /// The style. + /// The same instance so that multiple calls can be chained. + public static PercentageColumn Style(this PercentageColumn column, Style style) { - /// - /// Sets the style for a non-complete task. - /// - /// The column. - /// The style. - /// The same instance so that multiple calls can be chained. - public static PercentageColumn Style(this PercentageColumn column, Style style) + if (column is null) { - if (column is null) - { - throw new ArgumentNullException(nameof(column)); - } - - if (style is null) - { - throw new ArgumentNullException(nameof(style)); - } - - column.Style = style; - return column; + throw new ArgumentNullException(nameof(column)); } - /// - /// Sets the style for a completed task. - /// - /// The column. - /// The style. - /// The same instance so that multiple calls can be chained. - public static PercentageColumn CompletedStyle(this PercentageColumn column, Style style) + if (style is null) { - if (column is null) - { - throw new ArgumentNullException(nameof(column)); - } - - if (style is null) - { - throw new ArgumentNullException(nameof(style)); - } - - column.CompletedStyle = style; - return column; + throw new ArgumentNullException(nameof(style)); } + + column.Style = style; + return column; } -} + + /// + /// Sets the style for a completed task. + /// + /// The column. + /// The style. + /// The same instance so that multiple calls can be chained. + public static PercentageColumn CompletedStyle(this PercentageColumn column, Style style) + { + if (column is null) + { + throw new ArgumentNullException(nameof(column)); + } + + if (style is null) + { + throw new ArgumentNullException(nameof(style)); + } + + column.CompletedStyle = style; + return column; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/Progress/ProgressBarColumnExtensions.cs b/src/Spectre.Console/Extensions/Progress/ProgressBarColumnExtensions.cs index a58eb0f..314621a 100644 --- a/src/Spectre.Console/Extensions/Progress/ProgressBarColumnExtensions.cs +++ b/src/Spectre.Console/Extensions/Progress/ProgressBarColumnExtensions.cs @@ -1,76 +1,75 @@ using System; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class ProgressBarColumnExtensions { /// - /// Contains extension methods for . + /// Sets the style of completed portions of the progress bar. /// - public static class ProgressBarColumnExtensions + /// The column. + /// The style. + /// The same instance so that multiple calls can be chained. + public static ProgressBarColumn CompletedStyle(this ProgressBarColumn column, Style style) { - /// - /// Sets the style of completed portions of the progress bar. - /// - /// The column. - /// The style. - /// The same instance so that multiple calls can be chained. - public static ProgressBarColumn CompletedStyle(this ProgressBarColumn column, Style style) + if (column is null) { - if (column is null) - { - throw new ArgumentNullException(nameof(column)); - } - - if (style is null) - { - throw new ArgumentNullException(nameof(style)); - } - - column.CompletedStyle = style; - return column; + throw new ArgumentNullException(nameof(column)); } - /// - /// Sets the style of a finished progress bar. - /// - /// The column. - /// The style. - /// The same instance so that multiple calls can be chained. - public static ProgressBarColumn FinishedStyle(this ProgressBarColumn column, Style style) + if (style is null) { - if (column is null) - { - throw new ArgumentNullException(nameof(column)); - } - - if (style is null) - { - throw new ArgumentNullException(nameof(style)); - } - - column.FinishedStyle = style; - return column; + throw new ArgumentNullException(nameof(style)); } - /// - /// Sets the style of remaining portions of the progress bar. - /// - /// The column. - /// The style. - /// The same instance so that multiple calls can be chained. - public static ProgressBarColumn RemainingStyle(this ProgressBarColumn column, Style style) - { - if (column is null) - { - throw new ArgumentNullException(nameof(column)); - } - - if (style is null) - { - throw new ArgumentNullException(nameof(style)); - } - - column.RemainingStyle = style; - return column; - } + column.CompletedStyle = style; + return column; } -} + + /// + /// Sets the style of a finished progress bar. + /// + /// The column. + /// The style. + /// The same instance so that multiple calls can be chained. + public static ProgressBarColumn FinishedStyle(this ProgressBarColumn column, Style style) + { + if (column is null) + { + throw new ArgumentNullException(nameof(column)); + } + + if (style is null) + { + throw new ArgumentNullException(nameof(style)); + } + + column.FinishedStyle = style; + return column; + } + + /// + /// Sets the style of remaining portions of the progress bar. + /// + /// The column. + /// The style. + /// The same instance so that multiple calls can be chained. + public static ProgressBarColumn RemainingStyle(this ProgressBarColumn column, Style style) + { + if (column is null) + { + throw new ArgumentNullException(nameof(column)); + } + + if (style is null) + { + throw new ArgumentNullException(nameof(style)); + } + + column.RemainingStyle = style; + return column; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/Progress/ProgressExtensions.cs b/src/Spectre.Console/Extensions/Progress/ProgressExtensions.cs index 1172e53..14ee9de 100644 --- a/src/Spectre.Console/Extensions/Progress/ProgressExtensions.cs +++ b/src/Spectre.Console/Extensions/Progress/ProgressExtensions.cs @@ -1,99 +1,98 @@ using System; using System.Linq; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class ProgressExtensions { /// - /// Contains extension methods for . + /// Sets the columns to be used for an instance. /// - public static class ProgressExtensions + /// The instance. + /// The columns to use. + /// The same instance so that multiple calls can be chained. + public static Progress Columns(this Progress progress, params ProgressColumn[] columns) { - /// - /// Sets the columns to be used for an instance. - /// - /// The instance. - /// The columns to use. - /// The same instance so that multiple calls can be chained. - public static Progress Columns(this Progress progress, params ProgressColumn[] columns) + if (progress is null) { - if (progress is null) - { - throw new ArgumentNullException(nameof(progress)); - } - - if (columns is null) - { - throw new ArgumentNullException(nameof(columns)); - } - - if (!columns.Any()) - { - throw new InvalidOperationException("At least one column must be specified."); - } - - progress.Columns.Clear(); - progress.Columns.AddRange(columns); - - return progress; + throw new ArgumentNullException(nameof(progress)); } - /// - /// Sets whether or not auto refresh is enabled. - /// If disabled, you will manually have to refresh the progress. - /// - /// The instance. - /// Whether or not auto refresh is enabled. - /// The same instance so that multiple calls can be chained. - public static Progress AutoRefresh(this Progress progress, bool enabled) + if (columns is null) { - if (progress is null) - { - throw new ArgumentNullException(nameof(progress)); - } - - progress.AutoRefresh = enabled; - - return progress; + throw new ArgumentNullException(nameof(columns)); } - /// - /// Sets whether or not auto clear is enabled. - /// If enabled, the task tabled will be removed once - /// all tasks have completed. - /// - /// The instance. - /// Whether or not auto clear is enabled. - /// The same instance so that multiple calls can be chained. - public static Progress AutoClear(this Progress progress, bool enabled) + if (!columns.Any()) { - if (progress is null) - { - throw new ArgumentNullException(nameof(progress)); - } - - progress.AutoClear = enabled; - - return progress; + throw new InvalidOperationException("At least one column must be specified."); } - /// - /// Sets whether or not hide completed is enabled. - /// If enabled, the task tabled will be removed once it is - /// completed. - /// - /// The instance. - /// Whether or not hide completed is enabled. - /// The same instance so that multiple calls can be chained. - public static Progress HideCompleted(this Progress progress, bool enabled) - { - if (progress is null) - { - throw new ArgumentNullException(nameof(progress)); - } + progress.Columns.Clear(); + progress.Columns.AddRange(columns); - progress.HideCompleted = enabled; - - return progress; - } + return progress; } -} + + /// + /// Sets whether or not auto refresh is enabled. + /// If disabled, you will manually have to refresh the progress. + /// + /// The instance. + /// Whether or not auto refresh is enabled. + /// The same instance so that multiple calls can be chained. + public static Progress AutoRefresh(this Progress progress, bool enabled) + { + if (progress is null) + { + throw new ArgumentNullException(nameof(progress)); + } + + progress.AutoRefresh = enabled; + + return progress; + } + + /// + /// Sets whether or not auto clear is enabled. + /// If enabled, the task tabled will be removed once + /// all tasks have completed. + /// + /// The instance. + /// Whether or not auto clear is enabled. + /// The same instance so that multiple calls can be chained. + public static Progress AutoClear(this Progress progress, bool enabled) + { + if (progress is null) + { + throw new ArgumentNullException(nameof(progress)); + } + + progress.AutoClear = enabled; + + return progress; + } + + /// + /// Sets whether or not hide completed is enabled. + /// If enabled, the task tabled will be removed once it is + /// completed. + /// + /// The instance. + /// Whether or not hide completed is enabled. + /// The same instance so that multiple calls can be chained. + public static Progress HideCompleted(this Progress progress, bool enabled) + { + if (progress is null) + { + throw new ArgumentNullException(nameof(progress)); + } + + progress.HideCompleted = enabled; + + return progress; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/Progress/ProgressTaskExtensions.cs b/src/Spectre.Console/Extensions/Progress/ProgressTaskExtensions.cs index cf7f5d1..5bf6b43 100644 --- a/src/Spectre.Console/Extensions/Progress/ProgressTaskExtensions.cs +++ b/src/Spectre.Console/Extensions/Progress/ProgressTaskExtensions.cs @@ -1,78 +1,77 @@ using System; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class ProgressTaskExtensions { /// - /// Contains extension methods for . + /// Sets the task description. /// - public static class ProgressTaskExtensions + /// The task. + /// The description. + /// The same instance so that multiple calls can be chained. + public static ProgressTask Description(this ProgressTask task, string description) { - /// - /// Sets the task description. - /// - /// The task. - /// The description. - /// The same instance so that multiple calls can be chained. - public static ProgressTask Description(this ProgressTask task, string description) + if (task is null) { - if (task is null) - { - throw new ArgumentNullException(nameof(task)); - } - - task.Description = description; - return task; + throw new ArgumentNullException(nameof(task)); } - /// - /// Sets the max value of the task. - /// - /// The task. - /// The max value. - /// The same instance so that multiple calls can be chained. - public static ProgressTask MaxValue(this ProgressTask task, double value) - { - if (task is null) - { - throw new ArgumentNullException(nameof(task)); - } - - task.MaxValue = value; - return task; - } - - /// - /// Sets the value of the task. - /// - /// The task. - /// The value. - /// The same instance so that multiple calls can be chained. - public static ProgressTask Value(this ProgressTask task, double value) - { - if (task is null) - { - throw new ArgumentNullException(nameof(task)); - } - - task.Value = value; - return task; - } - - /// - /// Sets whether the task is considered indeterminate or not. - /// - /// The task. - /// Whether the task is considered indeterminate or not. - /// The same instance so that multiple calls can be chained. - public static ProgressTask IsIndeterminate(this ProgressTask task, bool indeterminate = true) - { - if (task is null) - { - throw new ArgumentNullException(nameof(task)); - } - - task.IsIndeterminate = indeterminate; - return task; - } + task.Description = description; + return task; } -} + + /// + /// Sets the max value of the task. + /// + /// The task. + /// The max value. + /// The same instance so that multiple calls can be chained. + public static ProgressTask MaxValue(this ProgressTask task, double value) + { + if (task is null) + { + throw new ArgumentNullException(nameof(task)); + } + + task.MaxValue = value; + return task; + } + + /// + /// Sets the value of the task. + /// + /// The task. + /// The value. + /// The same instance so that multiple calls can be chained. + public static ProgressTask Value(this ProgressTask task, double value) + { + if (task is null) + { + throw new ArgumentNullException(nameof(task)); + } + + task.Value = value; + return task; + } + + /// + /// Sets whether the task is considered indeterminate or not. + /// + /// The task. + /// Whether the task is considered indeterminate or not. + /// The same instance so that multiple calls can be chained. + public static ProgressTask IsIndeterminate(this ProgressTask task, bool indeterminate = true) + { + if (task is null) + { + throw new ArgumentNullException(nameof(task)); + } + + task.IsIndeterminate = indeterminate; + return task; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/Progress/RemainingTimeColumnExtensions.cs b/src/Spectre.Console/Extensions/Progress/RemainingTimeColumnExtensions.cs index a33a31b..c33b994 100644 --- a/src/Spectre.Console/Extensions/Progress/RemainingTimeColumnExtensions.cs +++ b/src/Spectre.Console/Extensions/Progress/RemainingTimeColumnExtensions.cs @@ -1,32 +1,31 @@ using System; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class RemainingTimeColumnExtensions { /// - /// Contains extension methods for . + /// Sets the style of the remaining time text. /// - public static class RemainingTimeColumnExtensions + /// The column. + /// The style. + /// The same instance so that multiple calls can be chained. + public static RemainingTimeColumn Style(this RemainingTimeColumn column, Style style) { - /// - /// Sets the style of the remaining time text. - /// - /// The column. - /// The style. - /// The same instance so that multiple calls can be chained. - public static RemainingTimeColumn Style(this RemainingTimeColumn column, Style style) + if (column is null) { - if (column is null) - { - throw new ArgumentNullException(nameof(column)); - } - - if (style is null) - { - throw new ArgumentNullException(nameof(style)); - } - - column.Style = style; - return column; + throw new ArgumentNullException(nameof(column)); } + + if (style is null) + { + throw new ArgumentNullException(nameof(style)); + } + + column.Style = style; + return column; } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/Progress/SpinnerColumnExtensions.cs b/src/Spectre.Console/Extensions/Progress/SpinnerColumnExtensions.cs index 291c438..8c4ea16 100644 --- a/src/Spectre.Console/Extensions/Progress/SpinnerColumnExtensions.cs +++ b/src/Spectre.Console/Extensions/Progress/SpinnerColumnExtensions.cs @@ -1,62 +1,61 @@ using System; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class SpinnerColumnExtensions { /// - /// Contains extension methods for . + /// Sets the style of the spinner. /// - public static class SpinnerColumnExtensions + /// The column. + /// The style. + /// The same instance so that multiple calls can be chained. + public static SpinnerColumn Style(this SpinnerColumn column, Style? style) { - /// - /// Sets the style of the spinner. - /// - /// The column. - /// The style. - /// The same instance so that multiple calls can be chained. - public static SpinnerColumn Style(this SpinnerColumn column, Style? style) + if (column is null) { - if (column is null) - { - throw new ArgumentNullException(nameof(column)); - } - - column.Style = style; - return column; + throw new ArgumentNullException(nameof(column)); } - /// - /// Sets the text that should be shown instead of the spinner - /// once a task completes. - /// - /// The column. - /// The text. - /// The same instance so that multiple calls can be chained. - public static SpinnerColumn CompletedText(this SpinnerColumn column, string? text) - { - if (column is null) - { - throw new ArgumentNullException(nameof(column)); - } - - column.CompletedText = text; - return column; - } - - /// - /// Sets the completed style of the spinner. - /// - /// The column. - /// The style. - /// The same instance so that multiple calls can be chained. - public static SpinnerColumn CompletedStyle(this SpinnerColumn column, Style? style) - { - if (column is null) - { - throw new ArgumentNullException(nameof(column)); - } - - column.CompletedStyle = style; - return column; - } + column.Style = style; + return column; } -} + + /// + /// Sets the text that should be shown instead of the spinner + /// once a task completes. + /// + /// The column. + /// The text. + /// The same instance so that multiple calls can be chained. + public static SpinnerColumn CompletedText(this SpinnerColumn column, string? text) + { + if (column is null) + { + throw new ArgumentNullException(nameof(column)); + } + + column.CompletedText = text; + return column; + } + + /// + /// Sets the completed style of the spinner. + /// + /// The column. + /// The style. + /// The same instance so that multiple calls can be chained. + public static SpinnerColumn CompletedStyle(this SpinnerColumn column, Style? style) + { + if (column is null) + { + throw new ArgumentNullException(nameof(column)); + } + + column.CompletedStyle = style; + return column; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/Progress/StatusContextExtensions.cs b/src/Spectre.Console/Extensions/Progress/StatusContextExtensions.cs index a4d4f95..7e73b95 100644 --- a/src/Spectre.Console/Extensions/Progress/StatusContextExtensions.cs +++ b/src/Spectre.Console/Extensions/Progress/StatusContextExtensions.cs @@ -1,61 +1,60 @@ using System; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class StatusContextExtensions { /// - /// Contains extension methods for . + /// Sets the status message. /// - public static class StatusContextExtensions + /// The status context. + /// The status message. + /// The same instance so that multiple calls can be chained. + public static StatusContext Status(this StatusContext context, string status) { - /// - /// Sets the status message. - /// - /// The status context. - /// The status message. - /// The same instance so that multiple calls can be chained. - public static StatusContext Status(this StatusContext context, string status) + if (context is null) { - if (context is null) - { - throw new ArgumentNullException(nameof(context)); - } - - context.Status = status; - return context; + throw new ArgumentNullException(nameof(context)); } - /// - /// Sets the spinner. - /// - /// The status context. - /// The spinner. - /// The same instance so that multiple calls can be chained. - public static StatusContext Spinner(this StatusContext context, Spinner spinner) - { - if (context is null) - { - throw new ArgumentNullException(nameof(context)); - } - - context.Spinner = spinner; - return context; - } - - /// - /// Sets the spinner style. - /// - /// The status context. - /// The spinner style. - /// The same instance so that multiple calls can be chained. - public static StatusContext SpinnerStyle(this StatusContext context, Style? style) - { - if (context is null) - { - throw new ArgumentNullException(nameof(context)); - } - - context.SpinnerStyle = style; - return context; - } + context.Status = status; + return context; } -} + + /// + /// Sets the spinner. + /// + /// The status context. + /// The spinner. + /// The same instance so that multiple calls can be chained. + public static StatusContext Spinner(this StatusContext context, Spinner spinner) + { + if (context is null) + { + throw new ArgumentNullException(nameof(context)); + } + + context.Spinner = spinner; + return context; + } + + /// + /// Sets the spinner style. + /// + /// The status context. + /// The spinner style. + /// The same instance so that multiple calls can be chained. + public static StatusContext SpinnerStyle(this StatusContext context, Style? style) + { + if (context is null) + { + throw new ArgumentNullException(nameof(context)); + } + + context.SpinnerStyle = style; + return context; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/Progress/StatusExtensions.cs b/src/Spectre.Console/Extensions/Progress/StatusExtensions.cs index ab0a996..bc88c22 100644 --- a/src/Spectre.Console/Extensions/Progress/StatusExtensions.cs +++ b/src/Spectre.Console/Extensions/Progress/StatusExtensions.cs @@ -1,62 +1,61 @@ using System; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class StatusExtensions { /// - /// Contains extension methods for . + /// Sets whether or not auto refresh is enabled. + /// If disabled, you will manually have to refresh the progress. /// - public static class StatusExtensions + /// The instance. + /// Whether or not auto refresh is enabled. + /// The same instance so that multiple calls can be chained. + public static Status AutoRefresh(this Status status, bool enabled) { - /// - /// Sets whether or not auto refresh is enabled. - /// If disabled, you will manually have to refresh the progress. - /// - /// The instance. - /// Whether or not auto refresh is enabled. - /// The same instance so that multiple calls can be chained. - public static Status AutoRefresh(this Status status, bool enabled) + if (status is null) { - if (status is null) - { - throw new ArgumentNullException(nameof(status)); - } - - status.AutoRefresh = enabled; - return status; + throw new ArgumentNullException(nameof(status)); } - /// - /// Sets the spinner. - /// - /// The instance. - /// The spinner. - /// The same instance so that multiple calls can be chained. - public static Status Spinner(this Status status, Spinner spinner) - { - if (status is null) - { - throw new ArgumentNullException(nameof(status)); - } - - status.Spinner = spinner; - return status; - } - - /// - /// Sets the spinner style. - /// - /// The instance. - /// The spinner style. - /// The same instance so that multiple calls can be chained. - public static Status SpinnerStyle(this Status status, Style? style) - { - if (status is null) - { - throw new ArgumentNullException(nameof(status)); - } - - status.SpinnerStyle = style; - return status; - } + status.AutoRefresh = enabled; + return status; } -} + + /// + /// Sets the spinner. + /// + /// The instance. + /// The spinner. + /// The same instance so that multiple calls can be chained. + public static Status Spinner(this Status status, Spinner spinner) + { + if (status is null) + { + throw new ArgumentNullException(nameof(status)); + } + + status.Spinner = spinner; + return status; + } + + /// + /// Sets the spinner style. + /// + /// The instance. + /// The spinner style. + /// The same instance so that multiple calls can be chained. + public static Status SpinnerStyle(this Status status, Style? style) + { + if (status is null) + { + throw new ArgumentNullException(nameof(status)); + } + + status.SpinnerStyle = style; + return status; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/RecorderExtensions.cs b/src/Spectre.Console/Extensions/RecorderExtensions.cs index 4b432a5..f9a6230 100644 --- a/src/Spectre.Console/Extensions/RecorderExtensions.cs +++ b/src/Spectre.Console/Extensions/RecorderExtensions.cs @@ -1,44 +1,43 @@ using System; using Spectre.Console.Internal; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class RecorderExtensions { + private static readonly TextEncoder _textEncoder = new TextEncoder(); + private static readonly HtmlEncoder _htmlEncoder = new HtmlEncoder(); + /// - /// Contains extension methods for . + /// Exports the recorded content as text. /// - public static class RecorderExtensions + /// The recorder. + /// The recorded content as text. + public static string ExportText(this Recorder recorder) { - private static readonly TextEncoder _textEncoder = new TextEncoder(); - private static readonly HtmlEncoder _htmlEncoder = new HtmlEncoder(); - - /// - /// Exports the recorded content as text. - /// - /// The recorder. - /// The recorded content as text. - public static string ExportText(this Recorder recorder) + if (recorder is null) { - if (recorder is null) - { - throw new ArgumentNullException(nameof(recorder)); - } - - return recorder.Export(_textEncoder); + throw new ArgumentNullException(nameof(recorder)); } - /// - /// Exports the recorded content as HTML. - /// - /// The recorder. - /// The recorded content as HTML. - public static string ExportHtml(this Recorder recorder) - { - if (recorder is null) - { - throw new ArgumentNullException(nameof(recorder)); - } - - return recorder.Export(_htmlEncoder); - } + return recorder.Export(_textEncoder); } -} + + /// + /// Exports the recorded content as HTML. + /// + /// The recorder. + /// The recorded content as HTML. + public static string ExportHtml(this Recorder recorder) + { + if (recorder is null) + { + throw new ArgumentNullException(nameof(recorder)); + } + + return recorder.Export(_htmlEncoder); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/RenderableExtensions.cs b/src/Spectre.Console/Extensions/RenderableExtensions.cs index acc2fa5..73d6c4b 100644 --- a/src/Spectre.Console/Extensions/RenderableExtensions.cs +++ b/src/Spectre.Console/Extensions/RenderableExtensions.cs @@ -2,46 +2,45 @@ using System; using System.Collections.Generic; using Spectre.Console.Rendering; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class RenderableExtensions { /// - /// Contains extension methods for . + /// Gets the segments for a renderable using the specified console. /// - public static class RenderableExtensions + /// The renderable. + /// The console. + /// An enumerable containing segments representing the specified . + public static IEnumerable GetSegments(this IRenderable renderable, IAnsiConsole console) { - /// - /// Gets the segments for a renderable using the specified console. - /// - /// The renderable. - /// The console. - /// An enumerable containing segments representing the specified . - public static IEnumerable GetSegments(this IRenderable renderable, IAnsiConsole console) + if (console is null) { - if (console is null) - { - throw new ArgumentNullException(nameof(console)); - } - - if (renderable is null) - { - throw new ArgumentNullException(nameof(renderable)); - } - - var context = new RenderContext(console.Profile.Capabilities); - var renderables = console.Pipeline.Process(context, new[] { renderable }); - - return GetSegments(console, context, renderables); + throw new ArgumentNullException(nameof(console)); } - private static IEnumerable GetSegments(IAnsiConsole console, RenderContext options, IEnumerable renderables) + if (renderable is null) { - var result = new List(); - foreach (var renderable in renderables) - { - result.AddRange(renderable.Render(options, console.Profile.Width)); - } - - return Segment.Merge(result); + throw new ArgumentNullException(nameof(renderable)); } + + var context = new RenderContext(console.Profile.Capabilities); + var renderables = console.Pipeline.Process(context, new[] { renderable }); + + return GetSegments(console, context, renderables); } -} + + private static IEnumerable GetSegments(IAnsiConsole console, RenderContext options, IEnumerable renderables) + { + var result = new List(); + foreach (var renderable in renderables) + { + result.AddRange(renderable.Render(options, console.Profile.Width)); + } + + return Segment.Merge(result); + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/RuleExtensions.cs b/src/Spectre.Console/Extensions/RuleExtensions.cs index 917ad34..fff2863 100644 --- a/src/Spectre.Console/Extensions/RuleExtensions.cs +++ b/src/Spectre.Console/Extensions/RuleExtensions.cs @@ -1,54 +1,53 @@ using System; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class RuleExtensions { /// - /// Contains extension methods for . + /// Sets the rule title. /// - public static class RuleExtensions + /// The rule. + /// The title. + /// The same instance so that multiple calls can be chained. + public static Rule RuleTitle(this Rule rule, string title) { - /// - /// Sets the rule title. - /// - /// The rule. - /// The title. - /// The same instance so that multiple calls can be chained. - public static Rule RuleTitle(this Rule rule, string title) + if (rule is null) { - if (rule is null) - { - throw new ArgumentNullException(nameof(rule)); - } - - if (title is null) - { - throw new ArgumentNullException(nameof(title)); - } - - rule.Title = title; - return rule; + throw new ArgumentNullException(nameof(rule)); } - /// - /// Sets the rule style. - /// - /// The rule. - /// The rule style. - /// The same instance so that multiple calls can be chained. - public static Rule RuleStyle(this Rule rule, Style style) + if (title is null) { - if (rule is null) - { - throw new ArgumentNullException(nameof(rule)); - } - - if (style is null) - { - throw new ArgumentNullException(nameof(style)); - } - - rule.Style = style; - return rule; + throw new ArgumentNullException(nameof(title)); } + + rule.Title = title; + return rule; } -} + + /// + /// Sets the rule style. + /// + /// The rule. + /// The rule style. + /// The same instance so that multiple calls can be chained. + public static Rule RuleStyle(this Rule rule, Style style) + { + if (rule is null) + { + throw new ArgumentNullException(nameof(rule)); + } + + if (style is null) + { + throw new ArgumentNullException(nameof(style)); + } + + rule.Style = style; + return rule; + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/StackExtensions.cs b/src/Spectre.Console/Extensions/StackExtensions.cs index 6385db4..afac5fe 100644 --- a/src/Spectre.Console/Extensions/StackExtensions.cs +++ b/src/Spectre.Console/Extensions/StackExtensions.cs @@ -1,24 +1,23 @@ using System; using System.Collections.Generic; -namespace Spectre.Console -{ - internal static class StackExtensions - { - public static void PushRange(this Stack stack, IEnumerable source) - { - if (stack is null) - { - throw new ArgumentNullException(nameof(stack)); - } +namespace Spectre.Console; - if (source != null) +internal static class StackExtensions +{ + public static void PushRange(this Stack stack, IEnumerable source) + { + if (stack is null) + { + throw new ArgumentNullException(nameof(stack)); + } + + if (source != null) + { + foreach (var item in source) { - foreach (var item in source) - { - stack.Push(item); - } + stack.Push(item); } } } -} +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/StringBuilderExtensions.cs b/src/Spectre.Console/Extensions/StringBuilderExtensions.cs index 8db370b..97448da 100644 --- a/src/Spectre.Console/Extensions/StringBuilderExtensions.cs +++ b/src/Spectre.Console/Extensions/StringBuilderExtensions.cs @@ -2,40 +2,39 @@ using System; using System.Globalization; using System.Text; -namespace Spectre.Console +namespace Spectre.Console; + +internal static class StringBuilderExtensions { - internal static class StringBuilderExtensions + public static StringBuilder AppendWithStyle(this StringBuilder builder, Style? style, int? value) { - public static StringBuilder AppendWithStyle(this StringBuilder builder, Style? style, int? value) - { - return AppendWithStyle(builder, style, value?.ToString(CultureInfo.InvariantCulture)); - } - - public static StringBuilder AppendWithStyle(this StringBuilder builder, Style? style, string? value) - { - value ??= string.Empty; - - if (style != null) - { - return builder.Append('[') - .Append(style.ToMarkup()) - .Append(']') - .Append(value.EscapeMarkup()) - .Append("[/]"); - } - - return builder.Append(value); - } - - public static void AppendSpan(this StringBuilder builder, ReadOnlySpan span) - { - // NetStandard 2 lacks the override for StringBuilder to add the span. We'll need to convert the span - // to a string for it, but for .NET 5.0 we'll use the override. -#if NETSTANDARD2_0 - builder.Append(span.ToString()); -#else - builder.Append(span); -#endif - } + return AppendWithStyle(builder, style, value?.ToString(CultureInfo.InvariantCulture)); } -} + + public static StringBuilder AppendWithStyle(this StringBuilder builder, Style? style, string? value) + { + value ??= string.Empty; + + if (style != null) + { + return builder.Append('[') + .Append(style.ToMarkup()) + .Append(']') + .Append(value.EscapeMarkup()) + .Append("[/]"); + } + + return builder.Append(value); + } + + public static void AppendSpan(this StringBuilder builder, ReadOnlySpan span) + { + // NetStandard 2 lacks the override for StringBuilder to add the span. We'll need to convert the span + // to a string for it, but for .NET 5.0 we'll use the override. +#if NETSTANDARD2_0 + builder.Append(span.ToString()); +#else + builder.Append(span); +#endif + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/StringExtensions.cs b/src/Spectre.Console/Extensions/StringExtensions.cs index 4000851..85df022 100644 --- a/src/Spectre.Console/Extensions/StringExtensions.cs +++ b/src/Spectre.Console/Extensions/StringExtensions.cs @@ -4,193 +4,192 @@ using System.Globalization; using System.Linq; using System.Text; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class StringExtensions { + // Cache whether or not internally normalized line endings + // already are normalized. No reason to do yet another replace if it is. + private static readonly bool _alreadyNormalized + = Environment.NewLine.Equals("\n", StringComparison.OrdinalIgnoreCase); + /// - /// Contains extension methods for . + /// Escapes text so that it won’t be interpreted as markup. /// - public static class StringExtensions + /// The text to escape. + /// A string that is safe to use in markup. + public static string EscapeMarkup(this string? text) { - // Cache whether or not internally normalized line endings - // already are normalized. No reason to do yet another replace if it is. - private static readonly bool _alreadyNormalized - = Environment.NewLine.Equals("\n", StringComparison.OrdinalIgnoreCase); - - /// - /// Escapes text so that it won’t be interpreted as markup. - /// - /// The text to escape. - /// A string that is safe to use in markup. - public static string EscapeMarkup(this string? text) + if (text == null) { - if (text == null) - { - return string.Empty; - } - - return text - .ReplaceExact("[", "[[") - .ReplaceExact("]", "]]"); + return string.Empty; } - /// - /// Removes markup from the specified string. - /// - /// The text to remove markup from. - /// A string that does not have any markup. - public static string RemoveMarkup(this string? text) - { - if (string.IsNullOrWhiteSpace(text)) - { - return string.Empty; - } - - var result = new StringBuilder(); - - var tokenizer = new MarkupTokenizer(text); - while (tokenizer.MoveNext() && tokenizer.Current != null) - { - if (tokenizer.Current.Kind == MarkupTokenKind.Text) - { - result.Append(tokenizer.Current.Value); - } - } - - return result.ToString(); - } - - /// - /// Gets the cell width of the specified text. - /// - /// The text to get the cell width of. - /// The cell width of the text. - public static int GetCellWidth(this string text) - { - return Cell.GetCellLength(text); - } - - internal static string CapitalizeFirstLetter(this string? text, CultureInfo? culture = null) - { - if (text == null) - { - return string.Empty; - } - - culture ??= CultureInfo.InvariantCulture; - - if (text.Length > 0 && char.IsLower(text[0])) - { - text = string.Format(culture, "{0}{1}", char.ToUpper(text[0], culture), text.Substring(1)); - } - - return text; - } - - internal static string? RemoveNewLines(this string? text) - { - return text?.ReplaceExact("\r\n", string.Empty) - ?.ReplaceExact("\n", string.Empty); - } - - internal static string NormalizeNewLines(this string? text, bool native = false) - { - text = text?.ReplaceExact("\r\n", "\n"); - text ??= string.Empty; - - if (native && !_alreadyNormalized) - { - text = text.ReplaceExact("\n", Environment.NewLine); - } - - return text; - } - - internal static string[] SplitLines(this string text) - { - var result = text?.NormalizeNewLines()?.Split(new[] { '\n' }, StringSplitOptions.None); - return result ?? Array.Empty(); - } - - internal static string[] SplitWords(this string word, StringSplitOptions options = StringSplitOptions.None) - { - var result = new List(); - - static string Read(StringBuffer reader, Func criteria) - { - var buffer = new StringBuilder(); - while (!reader.Eof) - { - var current = reader.Peek(); - if (!criteria(current)) - { - break; - } - - buffer.Append(reader.Read()); - } - - return buffer.ToString(); - } - - using (var reader = new StringBuffer(word)) - { - while (!reader.Eof) - { - var current = reader.Peek(); - if (char.IsWhiteSpace(current)) - { - var x = Read(reader, c => char.IsWhiteSpace(c)); - if (options != StringSplitOptions.RemoveEmptyEntries) - { - result.Add(x); - } - } - else - { - result.Add(Read(reader, c => !char.IsWhiteSpace(c))); - } - } - } - - return result.ToArray(); - } - - internal static string Repeat(this string text, int count) - { - if (text is null) - { - throw new ArgumentNullException(nameof(text)); - } - - if (count <= 0) - { - return string.Empty; - } - - if (count == 1) - { - return text; - } - - return string.Concat(Enumerable.Repeat(text, count)); - } - - internal static string ReplaceExact(this string text, string oldValue, string? newValue) - { -#if NETSTANDARD2_0 - return text.Replace(oldValue, newValue); -#else - return text.Replace(oldValue, newValue, StringComparison.Ordinal); -#endif - } - - internal static bool ContainsExact(this string text, string value) - { -#if NETSTANDARD2_0 - return text.Contains(value); -#else - return text.Contains(value, StringComparison.Ordinal); -#endif - } + return text + .ReplaceExact("[", "[[") + .ReplaceExact("]", "]]"); } -} + + /// + /// Removes markup from the specified string. + /// + /// The text to remove markup from. + /// A string that does not have any markup. + public static string RemoveMarkup(this string? text) + { + if (string.IsNullOrWhiteSpace(text)) + { + return string.Empty; + } + + var result = new StringBuilder(); + + var tokenizer = new MarkupTokenizer(text); + while (tokenizer.MoveNext() && tokenizer.Current != null) + { + if (tokenizer.Current.Kind == MarkupTokenKind.Text) + { + result.Append(tokenizer.Current.Value); + } + } + + return result.ToString(); + } + + /// + /// Gets the cell width of the specified text. + /// + /// The text to get the cell width of. + /// The cell width of the text. + public static int GetCellWidth(this string text) + { + return Cell.GetCellLength(text); + } + + internal static string CapitalizeFirstLetter(this string? text, CultureInfo? culture = null) + { + if (text == null) + { + return string.Empty; + } + + culture ??= CultureInfo.InvariantCulture; + + if (text.Length > 0 && char.IsLower(text[0])) + { + text = string.Format(culture, "{0}{1}", char.ToUpper(text[0], culture), text.Substring(1)); + } + + return text; + } + + internal static string? RemoveNewLines(this string? text) + { + return text?.ReplaceExact("\r\n", string.Empty) + ?.ReplaceExact("\n", string.Empty); + } + + internal static string NormalizeNewLines(this string? text, bool native = false) + { + text = text?.ReplaceExact("\r\n", "\n"); + text ??= string.Empty; + + if (native && !_alreadyNormalized) + { + text = text.ReplaceExact("\n", Environment.NewLine); + } + + return text; + } + + internal static string[] SplitLines(this string text) + { + var result = text?.NormalizeNewLines()?.Split(new[] { '\n' }, StringSplitOptions.None); + return result ?? Array.Empty(); + } + + internal static string[] SplitWords(this string word, StringSplitOptions options = StringSplitOptions.None) + { + var result = new List(); + + static string Read(StringBuffer reader, Func criteria) + { + var buffer = new StringBuilder(); + while (!reader.Eof) + { + var current = reader.Peek(); + if (!criteria(current)) + { + break; + } + + buffer.Append(reader.Read()); + } + + return buffer.ToString(); + } + + using (var reader = new StringBuffer(word)) + { + while (!reader.Eof) + { + var current = reader.Peek(); + if (char.IsWhiteSpace(current)) + { + var x = Read(reader, c => char.IsWhiteSpace(c)); + if (options != StringSplitOptions.RemoveEmptyEntries) + { + result.Add(x); + } + } + else + { + result.Add(Read(reader, c => !char.IsWhiteSpace(c))); + } + } + } + + return result.ToArray(); + } + + internal static string Repeat(this string text, int count) + { + if (text is null) + { + throw new ArgumentNullException(nameof(text)); + } + + if (count <= 0) + { + return string.Empty; + } + + if (count == 1) + { + return text; + } + + return string.Concat(Enumerable.Repeat(text, count)); + } + + internal static string ReplaceExact(this string text, string oldValue, string? newValue) + { +#if NETSTANDARD2_0 + return text.Replace(oldValue, newValue); +#else + return text.Replace(oldValue, newValue, StringComparison.Ordinal); +#endif + } + + internal static bool ContainsExact(this string text, string value) + { +#if NETSTANDARD2_0 + return text.Contains(value); +#else + return text.Contains(value, StringComparison.Ordinal); +#endif + } +} \ No newline at end of file diff --git a/src/Spectre.Console/Extensions/StyleExtensions.cs b/src/Spectre.Console/Extensions/StyleExtensions.cs index 01dd5d3..232cd14 100644 --- a/src/Spectre.Console/Extensions/StyleExtensions.cs +++ b/src/Spectre.Console/Extensions/StyleExtensions.cs @@ -1,108 +1,107 @@ using System; using System.Collections.Generic; -namespace Spectre.Console +namespace Spectre.Console; + +/// +/// Contains extension methods for . +/// +public static class StyleExtensions { /// - /// Contains extension methods for . + /// Creates a new style from the specified one with + /// the specified foreground color. /// - public static class StyleExtensions + /// The style. + /// The foreground color. + /// The same instance so that multiple calls can be chained. + public static Style Foreground(this Style style, Color color) { - /// - /// Creates a new style from the specified one with - /// the specified foreground color. - /// - /// The style. - /// The foreground color. - /// The same instance so that multiple calls can be chained. - public static Style Foreground(this Style style, Color color) + if (style is null) { - if (style is null) - { - throw new ArgumentNullException(nameof(style)); - } - - return new Style( - foreground: color, - background: style.Background, - decoration: style.Decoration); + throw new ArgumentNullException(nameof(style)); } - /// - /// Creates a new style from the specified one with - /// the specified background color. - /// - /// The style. - /// The background color. - /// The same instance so that multiple calls can be chained. - public static Style Background(this Style style, Color color) - { - if (style is null) - { - throw new ArgumentNullException(nameof(style)); - } - - return new Style( - foreground: style.Foreground, - background: color, - decoration: style.Decoration); - } - - /// - /// Creates a new style from the specified one with - /// the specified text decoration. - /// - /// The style. - /// The text decoration. - /// The same instance so that multiple calls can be chained. - public static Style Decoration(this Style style, Decoration decoration) - { - if (style is null) - { - throw new ArgumentNullException(nameof(style)); - } - - return new Style( - foreground: style.Foreground, - background: style.Background, - decoration: decoration); - } - - /// - /// Creates a new style from the specified one with - /// the specified link. - /// - /// The style. - /// The link. - /// The same instance so that multiple calls can be chained. - public static Style Link(this Style style, string link) - { - if (style is null) - { - throw new ArgumentNullException(nameof(style)); - } - - return new Style( - foreground: style.Foreground, - background: style.Background, - decoration: style.Decoration, - link: link); - } - - internal static Style Combine(this Style style, IEnumerable