mirror of
				https://github.com/nsnail/spectre.console.git
				synced 2025-10-31 09:09:25 +08:00 
			
		
		
		
	Use file scoped namespace declarations
This commit is contained in:
		 Patrik Svensson
					Patrik Svensson
				
			
				
					committed by
					
						 Phil Scott
						Phil Scott
					
				
			
			
				
	
			
			
			 Phil Scott
						Phil Scott
					
				
			
						parent
						
							1dbaf50935
						
					
				
				
					commit
					ec1188b837
				
			| @@ -30,6 +30,9 @@ trim_trailing_whitespace = false | |||||||
| end_of_line = lf | end_of_line = lf | ||||||
|  |  | ||||||
| [*.cs] | [*.cs] | ||||||
|  | # Prefer file scoped namespace declarations | ||||||
|  | csharp_style_namespace_declarations = file_scoped:warning | ||||||
|  |  | ||||||
| # Sort using and Import directives with System.* appearing first | # Sort using and Import directives with System.* appearing first | ||||||
| dotnet_sort_system_directives_first = true | dotnet_sort_system_directives_first = true | ||||||
| dotnet_separate_import_directive_groups = false | dotnet_separate_import_directive_groups = false | ||||||
|   | |||||||
| @@ -1,16 +1,15 @@ | |||||||
| using System.ComponentModel; | using System.ComponentModel; | ||||||
| using Spectre.Console.Cli; | 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")] | ||||||
|             [CommandOption("--count")] |         [DefaultValue(1)] | ||||||
|             [Description("The number of bars to print")] |         public int Count { get; set; } | ||||||
|             [DefaultValue(1)] |  | ||||||
|             public int Count { get; set; } |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,38 +1,37 @@ | |||||||
| using Spectre.Console.Cli; | 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(); |             config.AddDelegate("foo", Foo) | ||||||
|             app.Configure(config => |                 .WithDescription("Foos the bars"); | ||||||
|             { |  | ||||||
|                 config.AddDelegate("foo", Foo) |  | ||||||
|                     .WithDescription("Foos the bars"); |  | ||||||
|  |  | ||||||
|                 config.AddDelegate<BarSettings>("bar", Bar) |             config.AddDelegate<BarSettings>("bar", Bar) | ||||||
|                     .WithDescription("Bars the foos"); ; |                 .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) |         return 0; | ||||||
|         { |  | ||||||
|             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; |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -2,46 +2,45 @@ using System.ComponentModel; | |||||||
| using Demo.Utilities; | using Demo.Utilities; | ||||||
| using Spectre.Console.Cli; | using Spectre.Console.Cli; | ||||||
|  |  | ||||||
| namespace Demo.Commands | namespace Demo.Commands; | ||||||
|  |  | ||||||
|  | [Description("Add a NuGet package reference to the project.")] | ||||||
|  | public sealed class AddPackageCommand : Command<AddPackageCommand.Settings> | ||||||
| { | { | ||||||
|     [Description("Add a NuGet package reference to the project.")] |     public sealed class Settings : AddSettings | ||||||
|     public sealed class AddPackageCommand : Command<AddPackageCommand.Settings> |  | ||||||
|     { |     { | ||||||
|         public sealed class Settings : AddSettings |         [CommandArgument(0, "<PACKAGENAME>")] | ||||||
|         { |         [Description("The package reference to add.")] | ||||||
|             [CommandArgument(0, "<PACKAGENAME>")] |         public string PackageName { get; set; } | ||||||
|             [Description("The package reference to add.")] |  | ||||||
|             public string PackageName { get; set; } |  | ||||||
|  |  | ||||||
|             [CommandOption("-v|--version <VERSION>")] |         [CommandOption("-v|--version <VERSION>")] | ||||||
|             [Description("The version of the package to add.")] |         [Description("The version of the package to add.")] | ||||||
|             public string Version { get; set; } |         public string Version { get; set; } | ||||||
|  |  | ||||||
|             [CommandOption("-f|--framework <FRAMEWORK>")] |         [CommandOption("-f|--framework <FRAMEWORK>")] | ||||||
|             [Description("Add the reference only when targeting a specific framework.")] |         [Description("Add the reference only when targeting a specific framework.")] | ||||||
|             public string Framework { get; set; } |         public string Framework { get; set; } | ||||||
|  |  | ||||||
|             [CommandOption("--no-restore")] |         [CommandOption("--no-restore")] | ||||||
|             [Description("Add the reference without performing restore preview and compatibility check.")] |         [Description("Add the reference without performing restore preview and compatibility check.")] | ||||||
|             public bool NoRestore { get; set; } |         public bool NoRestore { get; set; } | ||||||
|  |  | ||||||
|             [CommandOption("--source <SOURCE>")] |         [CommandOption("--source <SOURCE>")] | ||||||
|             [Description("The NuGet package source to use during the restore.")] |         [Description("The NuGet package source to use during the restore.")] | ||||||
|             public string Source { get; set; } |         public string Source { get; set; } | ||||||
|  |  | ||||||
|             [CommandOption("--package-directory <PACKAGEDIR>")] |         [CommandOption("--package-directory <PACKAGEDIR>")] | ||||||
|             [Description("The directory to restore packages to.")] |         [Description("The directory to restore packages to.")] | ||||||
|             public string PackageDirectory { get; set; } |         public string PackageDirectory { get; set; } | ||||||
|  |  | ||||||
|             [CommandOption("--interactive")] |         [CommandOption("--interactive")] | ||||||
|             [Description("Allows the command to stop and wait for user input or action (for example to complete authentication).")] |         [Description("Allows the command to stop and wait for user input or action (for example to complete authentication).")] | ||||||
|             public bool Interactive { get; set; } |         public bool Interactive { get; set; } | ||||||
|         } |     } | ||||||
|  |  | ||||||
|         public override int Execute(CommandContext context, Settings settings) |     public override int Execute(CommandContext context, Settings settings) | ||||||
|         { |     { | ||||||
|             SettingsDumper.Dump(settings); |         SettingsDumper.Dump(settings); | ||||||
|             return 0; |         return 0; | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -2,29 +2,28 @@ using System.ComponentModel; | |||||||
| using Demo.Utilities; | using Demo.Utilities; | ||||||
| using Spectre.Console.Cli; | using Spectre.Console.Cli; | ||||||
|  |  | ||||||
| namespace Demo.Commands | namespace Demo.Commands; | ||||||
|  |  | ||||||
|  | public sealed class AddReferenceCommand : Command<AddReferenceCommand.Settings> | ||||||
| { | { | ||||||
|     public sealed class AddReferenceCommand : Command<AddReferenceCommand.Settings> |     public sealed class Settings : AddSettings | ||||||
|     { |     { | ||||||
|         public sealed class Settings : AddSettings |         [CommandArgument(0, "<PROJECTPATH>")] | ||||||
|         { |         [Description("The package reference to add.")] | ||||||
|             [CommandArgument(0, "<PROJECTPATH>")] |         public string ProjectPath { get; set; } | ||||||
|             [Description("The package reference to add.")] |  | ||||||
|             public string ProjectPath { get; set; } |  | ||||||
|  |  | ||||||
|             [CommandOption("-f|--framework <FRAMEWORK>")] |         [CommandOption("-f|--framework <FRAMEWORK>")] | ||||||
|             [Description("Add the reference only when targeting a specific framework.")] |         [Description("Add the reference only when targeting a specific framework.")] | ||||||
|             public string Framework { get; set; } |         public string Framework { get; set; } | ||||||
|  |  | ||||||
|             [CommandOption("--interactive")] |         [CommandOption("--interactive")] | ||||||
|             [Description("Allows the command to stop and wait for user input or action (for example to complete authentication).")] |         [Description("Allows the command to stop and wait for user input or action (for example to complete authentication).")] | ||||||
|             public bool Interactive { get; set; } |         public bool Interactive { get; set; } | ||||||
|         } |     } | ||||||
|  |  | ||||||
|         public override int Execute(CommandContext context, Settings settings) |     public override int Execute(CommandContext context, Settings settings) | ||||||
|         { |     { | ||||||
|             SettingsDumper.Dump(settings); |         SettingsDumper.Dump(settings); | ||||||
|             return 0; |         return 0; | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,12 +1,11 @@ | |||||||
| using System.ComponentModel; | using System.ComponentModel; | ||||||
| using Spectre.Console.Cli; | using Spectre.Console.Cli; | ||||||
|  |  | ||||||
| namespace Demo.Commands | namespace Demo.Commands; | ||||||
|  |  | ||||||
|  | public abstract class AddSettings : CommandSettings | ||||||
| { | { | ||||||
|     public abstract class AddSettings : CommandSettings |     [CommandArgument(0, "<PROJECT>")] | ||||||
|     { |     [Description("The project file to operate on. If a file is not specified, the command will search the current directory for one.")] | ||||||
|         [CommandArgument(0, "<PROJECT>")] |     public string Project { get; set; } | ||||||
|         [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; } |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -2,69 +2,68 @@ using System.ComponentModel; | |||||||
| using Demo.Utilities; | using Demo.Utilities; | ||||||
| using Spectre.Console.Cli; | using Spectre.Console.Cli; | ||||||
|  |  | ||||||
| namespace Demo.Commands | namespace Demo.Commands; | ||||||
|  |  | ||||||
|  | [Description("Build and run a .NET project output.")] | ||||||
|  | public sealed class RunCommand : Command<RunCommand.Settings> | ||||||
| { | { | ||||||
|     [Description("Build and run a .NET project output.")] |     public sealed class Settings : CommandSettings | ||||||
|     public sealed class RunCommand : Command<RunCommand.Settings> |  | ||||||
|     { |     { | ||||||
|         public sealed class Settings : CommandSettings |         [CommandOption("-c|--configuration <CONFIGURATION>")] | ||||||
|         { |         [Description("The configuration to run for. The default for most projects is '[grey]Debug[/]'.")] | ||||||
|             [CommandOption("-c|--configuration <CONFIGURATION>")] |         [DefaultValue("Debug")] | ||||||
|             [Description("The configuration to run for. The default for most projects is '[grey]Debug[/]'.")] |         public string Configuration { get; set; } | ||||||
|             [DefaultValue("Debug")] |  | ||||||
|             public string Configuration { get; set; } |  | ||||||
|  |  | ||||||
|             [CommandOption("-f|--framework <FRAMEWORK>")] |         [CommandOption("-f|--framework <FRAMEWORK>")] | ||||||
|             [Description("The target framework to run for. The target framework must also be specified in the project file.")] |         [Description("The target framework to run for. The target framework must also be specified in the project file.")] | ||||||
|             public string Framework { get; set; } |         public string Framework { get; set; } | ||||||
|  |  | ||||||
|             [CommandOption("-r|--runtime <RUNTIMEIDENTIFIER>")] |         [CommandOption("-r|--runtime <RUNTIMEIDENTIFIER>")] | ||||||
|             [Description("The target runtime to run for.")] |         [Description("The target runtime to run for.")] | ||||||
|             public string RuntimeIdentifier { get; set; } |         public string RuntimeIdentifier { get; set; } | ||||||
|  |  | ||||||
|             [CommandOption("-p|--project <PROJECTPATH>")] |         [CommandOption("-p|--project <PROJECTPATH>")] | ||||||
|             [Description("The path to the project file to run (defaults to the current directory if there is only one 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; } |         public string ProjectPath { get; set; } | ||||||
|  |  | ||||||
|             [CommandOption("--launch-profile <LAUNCHPROFILE>")] |         [CommandOption("--launch-profile <LAUNCHPROFILE>")] | ||||||
|             [Description("The name of the launch profile (if any) to use when launching the application.")] |         [Description("The name of the launch profile (if any) to use when launching the application.")] | ||||||
|             public string LaunchProfile { get; set; } |         public string LaunchProfile { get; set; } | ||||||
|  |  | ||||||
|             [CommandOption("--no-launch-profile")] |         [CommandOption("--no-launch-profile")] | ||||||
|             [Description("Do not attempt to use [grey]launchSettings.json[/] to configure the application.")] |         [Description("Do not attempt to use [grey]launchSettings.json[/] to configure the application.")] | ||||||
|             public bool NoLaunchProfile { get; set; } |         public bool NoLaunchProfile { get; set; } | ||||||
|  |  | ||||||
|             [CommandOption("--no-build")] |         [CommandOption("--no-build")] | ||||||
|             [Description("Do not build the project before running. Implies [grey]--no-restore[/].")] |         [Description("Do not build the project before running. Implies [grey]--no-restore[/].")] | ||||||
|             public bool NoBuild { get; set; } |         public bool NoBuild { get; set; } | ||||||
|  |  | ||||||
|             [CommandOption("--interactive")] |         [CommandOption("--interactive")] | ||||||
|             [Description("Allows the command to stop and wait for user input or action (for example to complete authentication).")] |         [Description("Allows the command to stop and wait for user input or action (for example to complete authentication).")] | ||||||
|             public string Interactive { get; set; } |         public string Interactive { get; set; } | ||||||
|  |  | ||||||
|             [CommandOption("--no-restore")] |         [CommandOption("--no-restore")] | ||||||
|             [Description("Do not restore the project before building.")] |         [Description("Do not restore the project before building.")] | ||||||
|             public bool NoRestore { get; set; } |         public bool NoRestore { get; set; } | ||||||
|  |  | ||||||
|             [CommandOption("--verbosity <VERBOSITY>")] |         [CommandOption("--verbosity <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[/].")] |         [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))] |         [TypeConverter(typeof(VerbosityConverter))] | ||||||
|             [DefaultValue(Verbosity.Normal)] |         [DefaultValue(Verbosity.Normal)] | ||||||
|             public Verbosity Verbosity { get; set; } |         public Verbosity Verbosity { get; set; } | ||||||
|  |  | ||||||
|             [CommandOption("--no-dependencies")] |         [CommandOption("--no-dependencies")] | ||||||
|             [Description("Do not restore project-to-project references and only restore the specified project.")] |         [Description("Do not restore project-to-project references and only restore the specified project.")] | ||||||
|             public bool NoDependencies { get; set; } |         public bool NoDependencies { get; set; } | ||||||
|  |  | ||||||
|             [CommandOption("--force")] |         [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[/].")] |         [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 bool Force { get; set; } | ||||||
|         } |     } | ||||||
|  |  | ||||||
|         public override int Execute(CommandContext context, Settings settings) |     public override int Execute(CommandContext context, Settings settings) | ||||||
|         { |     { | ||||||
|             SettingsDumper.Dump(settings); |         SettingsDumper.Dump(settings); | ||||||
|             return 0; |         return 0; | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -3,39 +3,38 @@ using System.ComponentModel; | |||||||
| using Demo.Utilities; | using Demo.Utilities; | ||||||
| using Spectre.Console.Cli; | 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<ServeCommand.Settings> | ||||||
| { | { | ||||||
|     [Description("Launches a web server in the current working directory and serves all files in it.")] |     public sealed class Settings : CommandSettings | ||||||
|     public sealed class ServeCommand : Command<ServeCommand.Settings> |  | ||||||
|     { |     { | ||||||
|         public sealed class Settings : CommandSettings |         [CommandOption("-p|--port <PORT>")] | ||||||
|         { |         [Description("Port to use. Defaults to [grey]8080[/]. Use [grey]0[/] for a dynamic port.")] | ||||||
|             [CommandOption("-p|--port <PORT>")] |         public int Port { get; set; } | ||||||
|             [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]")] |         [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.")] |         [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<string> OpenBrowser { get; set; } |         public FlagValue<string> 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; |                 Console.WriteLine($"Open in {browser}"); | ||||||
|                 if (browser != null) |             } | ||||||
|                 { |             else | ||||||
|                     Console.WriteLine($"Open in {browser}"); |             { | ||||||
|                 } |                 Console.WriteLine($"Open in default browser."); | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
|                     Console.WriteLine($"Open in default browser."); |  | ||||||
|                 } |  | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             SettingsDumper.Dump(settings); |  | ||||||
|             return 0; |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         SettingsDumper.Dump(settings); | ||||||
|  |         return 0; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,37 +1,36 @@ | |||||||
| using Demo.Commands; | using Demo.Commands; | ||||||
| using Spectre.Console.Cli; | 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(); |             config.SetApplicationName("fake-dotnet"); | ||||||
|             app.Configure(config => |             config.ValidateExamples(); | ||||||
|             { |             config.AddExample(new[] { "run", "--no-build" }); | ||||||
|                 config.SetApplicationName("fake-dotnet"); |  | ||||||
|                 config.ValidateExamples(); |  | ||||||
|                 config.AddExample(new[] { "run", "--no-build" }); |  | ||||||
|  |  | ||||||
|                 // Run |                 // Run | ||||||
|                 config.AddCommand<RunCommand>("run"); |                 config.AddCommand<RunCommand>("run"); | ||||||
|  |  | ||||||
|                 // Add |                 // Add | ||||||
|                 config.AddBranch<AddSettings>("add", add => |                 config.AddBranch<AddSettings>("add", add => | ||||||
|                 { |             { | ||||||
|                     add.SetDescription("Add a package or reference to a .NET project"); |                 add.SetDescription("Add a package or reference to a .NET project"); | ||||||
|                     add.AddCommand<AddPackageCommand>("package"); |                 add.AddCommand<AddPackageCommand>("package"); | ||||||
|                     add.AddCommand<AddReferenceCommand>("reference"); |                 add.AddCommand<AddReferenceCommand>("reference"); | ||||||
|                 }); |             }); | ||||||
|  |  | ||||||
|                 // Serve |                 // Serve | ||||||
|                 config.AddCommand<ServeCommand>("serve") |                 config.AddCommand<ServeCommand>("serve") | ||||||
|                     .WithExample(new[] { "serve", "-o", "firefox" }) |                 .WithExample(new[] { "serve", "-o", "firefox" }) | ||||||
|                     .WithExample(new[] { "serve", "--port", "80", "-o", "firefox" }); |                 .WithExample(new[] { "serve", "--port", "80", "-o", "firefox" }); | ||||||
|             }); |         }); | ||||||
|  |  | ||||||
|             return app.Run(args); |         return app.Run(args); | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,29 +1,28 @@ | |||||||
| using Spectre.Console; | using Spectre.Console; | ||||||
| using Spectre.Console.Cli; | 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(); |             var value = property.GetValue(settings) | ||||||
|             table.AddColumn("[grey]Name[/]"); |                 ?.ToString() | ||||||
|             table.AddColumn("[grey]Value[/]"); |                 ?.Replace("[", "[["); | ||||||
|  |  | ||||||
|             var properties = settings.GetType().GetProperties(); |             table.AddRow( | ||||||
|             foreach (var property in properties) |                 property.Name, | ||||||
|             { |                 value ?? "[grey]null[/]"); | ||||||
|                 var value = property.GetValue(settings) |  | ||||||
|                     ?.ToString() |  | ||||||
|                     ?.Replace("[", "[["); |  | ||||||
|  |  | ||||||
|                 table.AddRow( |  | ||||||
|                     property.Name, |  | ||||||
|                     value ?? "[grey]null[/]"); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             AnsiConsole.Write(table); |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         AnsiConsole.Write(table); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -3,24 +3,24 @@ using System.Collections.Generic; | |||||||
| using System.ComponentModel; | using System.ComponentModel; | ||||||
| using System.Globalization; | using System.Globalization; | ||||||
|  |  | ||||||
| namespace Demo | namespace Demo; | ||||||
|  |  | ||||||
|  | public enum Verbosity | ||||||
| { | { | ||||||
|     public enum Verbosity |     Quiet, | ||||||
|     { |     Minimal, | ||||||
|         Quiet, |     Normal, | ||||||
|         Minimal, |     Detailed, | ||||||
|         Normal, |     Diagnostic | ||||||
|         Detailed, | } | ||||||
|         Diagnostic |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     public sealed class VerbosityConverter : TypeConverter | public sealed class VerbosityConverter : TypeConverter | ||||||
|     { | { | ||||||
|         private readonly Dictionary<string, Verbosity> _lookup; |     private readonly Dictionary<string, Verbosity> _lookup; | ||||||
|  |  | ||||||
|         public VerbosityConverter() |     public VerbosityConverter() | ||||||
|         { |     { | ||||||
|             _lookup = new Dictionary<string, Verbosity>(StringComparer.OrdinalIgnoreCase) |         _lookup = new Dictionary<string, Verbosity>(StringComparer.OrdinalIgnoreCase) | ||||||
|             { |             { | ||||||
|                 { "q", Verbosity.Quiet }, |                 { "q", Verbosity.Quiet }, | ||||||
|                 { "quiet", Verbosity.Quiet }, |                 { "quiet", Verbosity.Quiet }, | ||||||
| @@ -33,22 +33,21 @@ namespace Demo | |||||||
|                 { "diag", Verbosity.Diagnostic }, |                 { "diag", Verbosity.Diagnostic }, | ||||||
|                 { "diagnostic", 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); |                 const string format = "The value '{0}' is not a valid verbosity."; | ||||||
|                 if (!result) |                 var message = string.Format(CultureInfo.InvariantCulture, format, value); | ||||||
|                 { |                 throw new InvalidOperationException(message); | ||||||
|                     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."); |             return verbosity; | ||||||
|         } |         } | ||||||
|  |         throw new NotSupportedException("Can't convert value to verbosity."); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,20 +1,19 @@ | |||||||
| using System; | using System; | ||||||
| using Spectre.Console.Cli; | using Spectre.Console.Cli; | ||||||
|  |  | ||||||
| namespace Spectre.Console.Examples | namespace Spectre.Console.Examples; | ||||||
| { |  | ||||||
|     public sealed class MyCommand : Command | public sealed class MyCommand : Command | ||||||
|     { | { | ||||||
|         public override int Execute(CommandContext context) |     public override int Execute(CommandContext context) | ||||||
|         { |     { | ||||||
|             if (!(context.Data is int data)) |         if (!(context.Data is int data)) | ||||||
|             { |         { | ||||||
|                 throw new InvalidOperationException("Command has no associated data."); |             throw new InvalidOperationException("Command has no associated data."); | ||||||
|                  |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             AnsiConsole.WriteLine("Value = {0}", data); |  | ||||||
|             return 0; |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         AnsiConsole.WriteLine("Value = {0}", data); | ||||||
|  |         return 0; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,24 +1,23 @@ | |||||||
| using System.Linq; | using System.Linq; | ||||||
| using Spectre.Console.Cli; | using Spectre.Console.Cli; | ||||||
|  |  | ||||||
| namespace Spectre.Console.Examples | 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<MyCommand>($"c{index}") |  | ||||||
|                         .WithDescription($"Prints the number {index}") |  | ||||||
|                         .WithData(index); |  | ||||||
|                 } |  | ||||||
|             }); |  | ||||||
|  |  | ||||||
|             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<MyCommand>($"c{index}") | ||||||
|  |                     .WithDescription($"Prints the number {index}") | ||||||
|  |                     .WithData(index); | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         return app.Run(args); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -2,29 +2,28 @@ using System; | |||||||
| using System.ComponentModel; | using System.ComponentModel; | ||||||
| using Spectre.Console.Cli; | using Spectre.Console.Cli; | ||||||
|  |  | ||||||
| namespace Spectre.Console.Examples | namespace Spectre.Console.Examples; | ||||||
|  |  | ||||||
|  | public sealed class DefaultCommand : Command<DefaultCommand.Settings> | ||||||
| { | { | ||||||
|     public sealed class DefaultCommand : Command<DefaultCommand.Settings> |     private readonly IGreeter _greeter; | ||||||
|  |  | ||||||
|  |     public sealed class Settings : CommandSettings | ||||||
|     { |     { | ||||||
|         private readonly IGreeter _greeter; |         [CommandOption("-n|--name <NAME>")] | ||||||
|  |         [Description("The person or thing to greet.")] | ||||||
|  |         [DefaultValue("World")] | ||||||
|  |         public string Name { get; set; } | ||||||
|  |     } | ||||||
|  |  | ||||||
|         public sealed class Settings : CommandSettings |     public DefaultCommand(IGreeter greeter) | ||||||
|         { |     { | ||||||
|             [CommandOption("-n|--name <NAME>")] |         _greeter = greeter ?? throw new ArgumentNullException(nameof(greeter)); | ||||||
|             [Description("The person or thing to greet.")] |     } | ||||||
|             [DefaultValue("World")] |  | ||||||
|             public string Name { get; set; } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         public DefaultCommand(IGreeter greeter) |     public override int Execute(CommandContext context, Settings settings) | ||||||
|         { |     { | ||||||
|             _greeter = greeter ?? throw new ArgumentNullException(nameof(greeter)); |         _greeter.Greet(settings.Name); | ||||||
|         } |         return 0; | ||||||
|  |  | ||||||
|         public override int Execute(CommandContext context, Settings settings) |  | ||||||
|         { |  | ||||||
|             _greeter.Greet(settings.Name); |  | ||||||
|             return 0; |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,15 +1,14 @@ | |||||||
| namespace Spectre.Console.Examples | namespace Spectre.Console.Examples; | ||||||
| { |  | ||||||
|     public interface IGreeter |  | ||||||
|     { |  | ||||||
|         void Greet(string name); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     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}!"); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -2,40 +2,39 @@ using System; | |||||||
| using Microsoft.Extensions.DependencyInjection; | using Microsoft.Extensions.DependencyInjection; | ||||||
| using Spectre.Console.Cli; | 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<object> func) | ||||||
|  |     { | ||||||
|  |         if (func is null) | ||||||
|         { |         { | ||||||
|             _builder = builder; |             throw new ArgumentNullException(nameof(func)); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         public ITypeResolver Build() |         _builder.AddSingleton(service, (provider) => func()); | ||||||
|         { |  | ||||||
|             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<object> func) |  | ||||||
|         { |  | ||||||
|             if (func is null) |  | ||||||
|             { |  | ||||||
|                 throw new ArgumentNullException(nameof(func)); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             _builder.AddSingleton(service, (provider) => func()); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -2,33 +2,32 @@ using System; | |||||||
| using Microsoft.Extensions.DependencyInjection; | using Microsoft.Extensions.DependencyInjection; | ||||||
| using Spectre.Console.Cli; | 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) |         return _provider.GetService(type); | ||||||
|         { |     } | ||||||
|             if (type == null) |  | ||||||
|             { |  | ||||||
|                 return null; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             return _provider.GetService(type); |     public void Dispose() | ||||||
|         } |     { | ||||||
|  |         if (_provider is IDisposable disposable) | ||||||
|         public void Dispose() |  | ||||||
|         { |         { | ||||||
|             if (_provider is IDisposable disposable) |             disposable.Dispose(); | ||||||
|             { |  | ||||||
|                 disposable.Dispose(); |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,22 +1,21 @@ | |||||||
| using Microsoft.Extensions.DependencyInjection; | using Microsoft.Extensions.DependencyInjection; | ||||||
| using Spectre.Console.Cli; | using Spectre.Console.Cli; | ||||||
|  |  | ||||||
| namespace Spectre.Console.Examples | 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<IGreeter, HelloWorldGreeter>(); |  | ||||||
|             var registrar = new TypeRegistrar(registrations); |  | ||||||
|  |  | ||||||
|             // Create a new command app with the registrar | public class Program | ||||||
|             // and run it with the provided arguments. | { | ||||||
|             var app = new CommandApp<DefaultCommand>(registrar); |     public static int Main(string[] args) | ||||||
|             return app.Run(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<IGreeter, HelloWorldGreeter>(); | ||||||
|  |         var registrar = new TypeRegistrar(registrations); | ||||||
|  |  | ||||||
|  |         // Create a new command app with the registrar | ||||||
|  |         // and run it with the provided arguments. | ||||||
|  |         var app = new CommandApp<DefaultCommand>(registrar); | ||||||
|  |         return app.Run(args); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,34 +1,33 @@ | |||||||
| using Microsoft.Extensions.Logging; | using Microsoft.Extensions.Logging; | ||||||
| using Spectre.Console.Cli; | using Spectre.Console.Cli; | ||||||
|  |  | ||||||
| namespace Spectre.Console.Examples | namespace Spectre.Console.Examples; | ||||||
|  |  | ||||||
|  | public class HelloCommand : Command<HelloCommand.Settings> | ||||||
| { | { | ||||||
|     public class HelloCommand : Command<HelloCommand.Settings> |     private ILogger<HelloCommand> _logger; | ||||||
|  |     private IAnsiConsole _console; | ||||||
|  |  | ||||||
|  |     public HelloCommand(IAnsiConsole console, ILogger<HelloCommand> logger) | ||||||
|     { |     { | ||||||
|         private ILogger<HelloCommand> _logger; |         _console = console; | ||||||
|         private IAnsiConsole _console; |         _logger = logger; | ||||||
|  |         _logger.LogDebug("{0} initialized", nameof(HelloCommand)); | ||||||
|         public HelloCommand(IAnsiConsole console, ILogger<HelloCommand> 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; |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } |  | ||||||
|  |     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; | ||||||
|  |     } | ||||||
|  | } | ||||||
|   | |||||||
| @@ -5,28 +5,28 @@ using System.Globalization; | |||||||
| using Serilog.Events; | using Serilog.Events; | ||||||
| using Spectre.Console.Cli; | 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<string, LogEventLevel> _lookup; | ||||||
|  |  | ||||||
|  |     public VerbosityConverter() | ||||||
|     { |     { | ||||||
|         [CommandOption("--logFile")] |         _lookup = new Dictionary<string, LogEventLevel>(StringComparer.OrdinalIgnoreCase) | ||||||
|         [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<string, LogEventLevel> _lookup; |  | ||||||
|  |  | ||||||
|         public VerbosityConverter() |  | ||||||
|         { |  | ||||||
|             _lookup = new Dictionary<string, LogEventLevel>(StringComparer.OrdinalIgnoreCase) |  | ||||||
|             { |             { | ||||||
|                 {"d", LogEventLevel.Debug}, |                 {"d", LogEventLevel.Debug}, | ||||||
|                 {"v", LogEventLevel.Verbose}, |                 {"v", LogEventLevel.Verbose}, | ||||||
| @@ -35,22 +35,21 @@ namespace Spectre.Console.Examples | |||||||
|                 {"e", LogEventLevel.Error}, |                 {"e", LogEventLevel.Error}, | ||||||
|                 {"f", LogEventLevel.Fatal} |                 {"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."); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } |  | ||||||
|  |     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."); | ||||||
|  |     } | ||||||
|  | } | ||||||
|   | |||||||
| @@ -1,19 +1,18 @@ | |||||||
| using Serilog.Core; | using Serilog.Core; | ||||||
| using Spectre.Console.Cli; | using Spectre.Console.Cli; | ||||||
|  |  | ||||||
| namespace Spectre.Console.Examples | namespace Spectre.Console.Examples; | ||||||
| { |  | ||||||
|     public class LogInterceptor : ICommandInterceptor |  | ||||||
|     { |  | ||||||
|         public static readonly LoggingLevelSwitch LogLevel = new(); |  | ||||||
|  |  | ||||||
|         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; |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,38 +1,37 @@ | |||||||
| using Serilog.Core; | using Serilog.Core; | ||||||
| using Serilog.Events; | 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; |         // the settings might not have a path or we might not be within a command in which case | ||||||
|         private LogEventProperty _cachedLogFilePathProperty; |         // 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 |         if (_cachedLogFilePathProperty != null && Path.Equals(_cachedLogFilePath)) | ||||||
|         public static string Path = string.Empty; |  | ||||||
|  |  | ||||||
|         public const string LogFilePathPropertyName = "LogFilePath"; |  | ||||||
|  |  | ||||||
|         public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) |  | ||||||
|         { |         { | ||||||
|             // the settings might not have a path or we might not be within a command in which case |             // Path hasn't changed, so let's use the cached property | ||||||
|             // we won't have the setting so a default value for the log file will be required |             logFilePathProperty = _cachedLogFilePathProperty; | ||||||
|             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); |  | ||||||
|         } |         } | ||||||
|  |         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); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -2,40 +2,39 @@ using System; | |||||||
| using Microsoft.Extensions.DependencyInjection; | using Microsoft.Extensions.DependencyInjection; | ||||||
| using Spectre.Console.Cli; | 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) |  | ||||||
|         { |  | ||||||
|             _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<object> func) |  | ||||||
|         { |  | ||||||
|             if (func is null) |  | ||||||
|             { |  | ||||||
|                 throw new ArgumentNullException(nameof(func)); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             _builder.AddSingleton(service, _ => 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<object> func) | ||||||
|  |     { | ||||||
|  |         if (func is null) | ||||||
|  |         { | ||||||
|  |             throw new ArgumentNullException(nameof(func)); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         _builder.AddSingleton(service, _ => func()); | ||||||
|  |     } | ||||||
|  | } | ||||||
|   | |||||||
| @@ -2,20 +2,19 @@ using System; | |||||||
| using Microsoft.Extensions.DependencyInjection; | using Microsoft.Extensions.DependencyInjection; | ||||||
| using Spectre.Console.Cli; | 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; |         _provider = provider ?? throw new ArgumentNullException(nameof(provider)); | ||||||
|  |  | ||||||
|         public TypeResolver(IServiceProvider provider) |  | ||||||
|         { |  | ||||||
|             _provider = provider ?? throw new ArgumentNullException(nameof(provider)); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         public object Resolve(Type type) |  | ||||||
|         { |  | ||||||
|             return _provider.GetRequiredService(type); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } |  | ||||||
|  |     public object Resolve(Type type) | ||||||
|  |     { | ||||||
|  |         return _provider.GetRequiredService(type); | ||||||
|  |     } | ||||||
|  | } | ||||||
|   | |||||||
| @@ -12,42 +12,41 @@ using Spectre.Console.Cli; | |||||||
|  * Spectre.Console CommandInterceptor |  * 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<LoggingEnricher>() | ||||||
|  |                     // 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 |             config.SetInterceptor(new LogInterceptor()); // add the interceptor | ||||||
|             // 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<LoggingEnricher>() |  | ||||||
|                         // 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.AddCommand<HelloCommand>("hello"); |                 config.AddCommand<HelloCommand>("hello"); | ||||||
|             }); |         }); | ||||||
|  |  | ||||||
|             return app.Run(args); |         return app.Run(args); | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,32 +1,32 @@ | |||||||
| using Spectre.Console.Rendering; | using Spectre.Console.Rendering; | ||||||
|  |  | ||||||
| namespace Spectre.Console.Examples | namespace Spectre.Console.Examples; | ||||||
| { |  | ||||||
|     public static class Program |  | ||||||
|     { |  | ||||||
|         public static void Main() |  | ||||||
|         { |  | ||||||
|             // Render panel borders |  | ||||||
|             HorizontalRule("PANEL BORDERS"); |  | ||||||
|             PanelBorders(); |  | ||||||
|  |  | ||||||
|             // Render table borders | public static class Program | ||||||
|             HorizontalRule("TABLE BORDERS"); | { | ||||||
|             TableBorders(); |     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("Ascii", BoxBorder.Ascii), | ||||||
|                 CreatePanel("Square", BoxBorder.Square), |                 CreatePanel("Square", BoxBorder.Square), | ||||||
|                 CreatePanel("Rounded", BoxBorder.Rounded), |                 CreatePanel("Rounded", BoxBorder.Rounded), | ||||||
| @@ -35,29 +35,29 @@ namespace Spectre.Console.Examples | |||||||
|                 CreatePanel("None", BoxBorder.None), |                 CreatePanel("None", BoxBorder.None), | ||||||
|             }; |             }; | ||||||
|  |  | ||||||
|             AnsiConsole.Write( |         AnsiConsole.Write( | ||||||
|                 new Padder( |             new Padder( | ||||||
|                     new Columns(items).PadRight(2), |                 new Columns(items).PadRight(2), | ||||||
|                     new Padding(2,0,0,0))); |                 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("Ascii", TableBorder.Ascii), | ||||||
|                 CreateTable("Ascii2", TableBorder.Ascii2), |                 CreateTable("Ascii2", TableBorder.Ascii2), | ||||||
|                 CreateTable("AsciiDoubleHead", TableBorder.AsciiDoubleHead), |                 CreateTable("AsciiDoubleHead", TableBorder.AsciiDoubleHead), | ||||||
| @@ -77,14 +77,13 @@ namespace Spectre.Console.Examples | |||||||
|                 CreateTable("Markdown", TableBorder.Markdown), |                 CreateTable("Markdown", TableBorder.Markdown), | ||||||
|             }; |             }; | ||||||
|  |  | ||||||
|             AnsiConsole.Write(new Columns(items).Collapse()); |         AnsiConsole.Write(new Columns(items).Collapse()); | ||||||
|         } |     } | ||||||
|  |  | ||||||
|         private static void HorizontalRule(string title) |     private static void HorizontalRule(string title) | ||||||
|         { |     { | ||||||
|             AnsiConsole.WriteLine(); |         AnsiConsole.WriteLine(); | ||||||
|             AnsiConsole.Write(new Rule($"[white bold]{title}[/]").RuleStyle("grey").LeftAligned()); |         AnsiConsole.Write(new Rule($"[white bold]{title}[/]").RuleStyle("grey").LeftAligned()); | ||||||
|             AnsiConsole.WriteLine(); |         AnsiConsole.WriteLine(); | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -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) | ||||||
|             AnsiConsole.WriteLine(); |                 .RoundedBorder() | ||||||
|             AnsiConsole.Write(new Calendar(2020, 10) |                 .HighlightStyle(Style.Parse("red")) | ||||||
|                     .RoundedBorder() |                 .HeaderStyle(Style.Parse("yellow")) | ||||||
|                     .HighlightStyle(Style.Parse("red")) |                 .AddCalendarEvent("An event", 2020, 9, 22) | ||||||
|                     .HeaderStyle(Style.Parse("yellow")) |                 .AddCalendarEvent("Another event", 2020, 10, 2) | ||||||
|                     .AddCalendarEvent("An event", 2020, 9, 22) |                 .AddCalendarEvent("A third event", 2020, 10, 13)); | ||||||
|                     .AddCalendarEvent("Another event", 2020, 10, 2) |  | ||||||
|                     .AddCalendarEvent("A third event", 2020, 10, 13)); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -5,82 +5,81 @@ Licensed under GNU Free Documentation License 1.2 | |||||||
|  |  | ||||||
| using System; | 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; } |             Real = real; | ||||||
|             public double Imaginary { get; } |             Imaginary = imaginary; | ||||||
|  |  | ||||||
|             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; |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         public static Canvas Generate(int width, int height) |         public static ComplexNumber operator +(ComplexNumber x, ComplexNumber y) | ||||||
|         { |         { | ||||||
|             var canvas = new Canvas(width, height); |             return new ComplexNumber(x.Real + y.Real, x.Imaginary + y.Imaginary); | ||||||
|  |  | ||||||
|             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) |         public static ComplexNumber operator *(ComplexNumber x, ComplexNumber y) | ||||||
|         { |         { | ||||||
|             const int MaxIterations = 1000; |             return new ComplexNumber(x.Real * y.Real - x.Imaginary * y.Imaginary, | ||||||
|             const double MaxNorm = MaxValueExtent * MaxValueExtent; |                 x.Real * y.Imaginary + x.Imaginary * y.Real); | ||||||
|  |  | ||||||
|             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) |         public double Abs() | ||||||
|         { |         { | ||||||
|             const double MaxColor = 256; |             return Real * Real + Imaginary * Imaginary; | ||||||
|             const double ContrastValue = 0.2; |  | ||||||
|             return new Color(0, 0, (byte)(MaxColor * Math.Pow(value, ContrastValue))); |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     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))); | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -3,45 +3,44 @@ using System.Reflection; | |||||||
| using SixLabors.ImageSharp.Processing; | using SixLabors.ImageSharp.Processing; | ||||||
| using Spectre.Console.Rendering; | 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 |             Debug.Assert(fileStream != null); | ||||||
|             var mandelbrot = Mandelbrot.Generate(32, 32); |             var embeddedImage = new CanvasImage(fileStream); | ||||||
|             Render(mandelbrot, "Mandelbrot"); |             embeddedImage.BilinearResampler(); | ||||||
|  |             embeddedImage.MaxWidth(16); | ||||||
|             // Draw an image using CanvasImage powered by ImageSharp. |             Render(embeddedImage, "Image from embedded resource (16 wide)"); | ||||||
|             // 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); |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     private static void Render(IRenderable canvas, string title) | ||||||
|  |     { | ||||||
|  |         AnsiConsole.WriteLine(); | ||||||
|  |         AnsiConsole.Write(new Rule($"[yellow]{title}[/]").LeftAligned().RuleStyle("grey")); | ||||||
|  |         AnsiConsole.WriteLine(); | ||||||
|  |         AnsiConsole.Write(canvas); | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,41 +1,40 @@ | |||||||
| using Spectre.Console.Rendering; | 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 a bar chart |         Render("Fruits per month", new BarChart() | ||||||
|             AnsiConsole.WriteLine(); |             .Width(60) | ||||||
|             Render("Fruits per month", new BarChart() |             .Label("[green bold underline]Number of fruits[/]") | ||||||
|                 .Width(60) |             .CenterLabel() | ||||||
|                 .Label("[green bold underline]Number of fruits[/]") |             .AddItem("Apple", 12, Color.Yellow) | ||||||
|                 .CenterLabel() |             .AddItem("Orange", 54, Color.Green) | ||||||
|                 .AddItem("Apple", 12, Color.Yellow) |             .AddItem("Banana", 33, Color.Red)); | ||||||
|                 .AddItem("Orange", 54, Color.Green) |  | ||||||
|                 .AddItem("Banana", 33, Color.Red)); |  | ||||||
|  |  | ||||||
|             // Render a breakdown chart |         // Render a breakdown chart | ||||||
|             AnsiConsole.WriteLine(); |         AnsiConsole.WriteLine(); | ||||||
|             Render("Languages used", new BreakdownChart() |         Render("Languages used", new BreakdownChart() | ||||||
|                 .FullSize() |             .FullSize() | ||||||
|                 .Width(60) |             .Width(60) | ||||||
|                 .ShowPercentage() |             .ShowPercentage() | ||||||
|                 .AddItem("SCSS", 37, Color.Red) |             .AddItem("SCSS", 37, Color.Red) | ||||||
|                 .AddItem("HTML", 28.3, Color.Blue) |             .AddItem("HTML", 28.3, Color.Blue) | ||||||
|                 .AddItem("C#", 22.6, Color.Green) |             .AddItem("C#", 22.6, Color.Green) | ||||||
|                 .AddItem("JavaScript", 6, Color.Yellow) |             .AddItem("JavaScript", 6, Color.Yellow) | ||||||
|                 .AddItem("Ruby", 6, Color.LightGreen) |             .AddItem("Ruby", 6, Color.LightGreen) | ||||||
|                 .AddItem("Shell", 0.1, Color.Aqua)); |             .AddItem("Shell", 0.1, Color.Aqua)); | ||||||
|         } |     } | ||||||
|  |  | ||||||
|         private static void Render(string title, IRenderable chart) |     private static void Render(string title, IRenderable chart) | ||||||
|         { |     { | ||||||
|             AnsiConsole.Write( |         AnsiConsole.Write( | ||||||
|                 new Panel(chart) |             new Panel(chart) | ||||||
|                     .Padding(1, 1) |                 .Padding(1, 1) | ||||||
|                     .Header(title)); |                 .Header(title)); | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -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) | ||||||
|         { |         { | ||||||
|             ///////////////////////////////////////////////////////////////// |             AnsiConsole.WriteLine("No colors are supported."); | ||||||
|             // No colors |             return; | ||||||
|             ///////////////////////////////////////////////////////////////// |         } | ||||||
|             if (AnsiConsole.Profile.Capabilities.ColorSystem == ColorSystem.NoColors) |  | ||||||
|             { |  | ||||||
|                 AnsiConsole.WriteLine("No colors are supported."); |  | ||||||
|                 return; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             ///////////////////////////////////////////////////////////////// |         ///////////////////////////////////////////////////////////////// | ||||||
|             // 3-BIT |         // 3-BIT | ||||||
|             ///////////////////////////////////////////////////////////////// |         ///////////////////////////////////////////////////////////////// | ||||||
|             if (AnsiConsole.Profile.Supports(ColorSystem.Legacy)) |         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.ResetColors(); | ||||||
|                 AnsiConsole.WriteLine(); |                 if ((i + 1) % 8 == 0) | ||||||
|                 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.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.Foreground = AnsiConsole.Background.GetInvertedColor(); | ||||||
|                     AnsiConsole.Write(string.Format(" {0,-9}", AnsiConsole.Background.ToString())); |                     AnsiConsole.Write(string.Format(" {0,-4}", number)); | ||||||
|                     AnsiConsole.ResetColors(); |                     AnsiConsole.ResetColors(); | ||||||
|                     if ((i + 1) % 8 == 0) |                     if ((number + 1) % 16 == 0) | ||||||
|                     { |                     { | ||||||
|                         AnsiConsole.WriteLine(); |                         AnsiConsole.WriteLine(); | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|             ///////////////////////////////////////////////////////////////// |         ///////////////////////////////////////////////////////////////// | ||||||
|             // 4-BIT |         // 24-BIT | ||||||
|             ///////////////////////////////////////////////////////////////// |         ///////////////////////////////////////////////////////////////// | ||||||
|             if (AnsiConsole.Profile.Supports(ColorSystem.Standard)) |         if (AnsiConsole.Profile.Supports(ColorSystem.TrueColor)) | ||||||
|             { |         { | ||||||
|                 AnsiConsole.ResetColors(); |             AnsiConsole.ResetColors(); | ||||||
|                 AnsiConsole.WriteLine(); |             AnsiConsole.WriteLine(); | ||||||
|                 AnsiConsole.Write(new Rule("[yellow bold underline]4-bit Colors[/]").RuleStyle("grey").LeftAligned()); |             AnsiConsole.Write(new Rule("[yellow bold underline]24-bit Colors[/]").RuleStyle("grey").LeftAligned()); | ||||||
|                 AnsiConsole.WriteLine(); |             AnsiConsole.WriteLine(); | ||||||
|  |  | ||||||
|                 for (var i = 0; i < 16; i++) |             AnsiConsole.Write(new ColorBox(width: 80, height: 15)); | ||||||
|                 { |  | ||||||
|                     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)); |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,30 +1,29 @@ | |||||||
| using System.Collections.Generic; | 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<Panel>(); | ||||||
|  |         foreach (var user in User.LoadUsers()) | ||||||
|         { |         { | ||||||
|             var cards = new List<Panel>(); |             cards.Add( | ||||||
|             foreach(var user in User.LoadUsers()) |                 new Panel(GetCardContent(user)) | ||||||
|             { |                     .Header($"{user.Country}") | ||||||
|                 cards.Add( |                     .RoundedBorder().Expand()); | ||||||
|                     new Panel(GetCardContent(user)) |  | ||||||
|                         .Header($"{user.Country}") |  | ||||||
|                         .RoundedBorder().Expand()); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             // Render all cards in columns |  | ||||||
|             AnsiConsole.Write(new Columns(cards)); |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         private static string GetCardContent(User user) |         // Render all cards in columns | ||||||
|         { |         AnsiConsole.Write(new Columns(cards)); | ||||||
|             var name = $"{user.FirstName} {user.LastName}"; |     } | ||||||
|             var city = $"{user.City}"; |  | ||||||
|  |  | ||||||
|             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}[/]"; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,17 +1,17 @@ | |||||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||||
|  |  | ||||||
| namespace Spectre.Console.Examples | 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; } |  | ||||||
|  |  | ||||||
|         public static List<User> LoadUsers() | public sealed class User | ||||||
|         { | { | ||||||
|             return new List<User> |     public string FirstName { get; set; } | ||||||
|  |     public string LastName { get; set; } | ||||||
|  |     public string City { get; set; } | ||||||
|  |     public string Country { get; set; } | ||||||
|  |  | ||||||
|  |     public static List<User> LoadUsers() | ||||||
|  |     { | ||||||
|  |         return new List<User> | ||||||
|             { |             { | ||||||
|                 new User |                 new User | ||||||
|                 { |                 { | ||||||
| @@ -84,6 +84,5 @@ namespace Spectre.Console.Examples | |||||||
|                     Country = "Ireland", |                     Country = "Ireland", | ||||||
|                 }, |                 }, | ||||||
|             }; |             }; | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -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 |         // Move the cursor 3 cells to the right | ||||||
|             AnsiConsole.Cursor.Move(CursorDirection.Right, 3); |         AnsiConsole.Cursor.Move(CursorDirection.Right, 3); | ||||||
|             AnsiConsole.Write("World"); |         AnsiConsole.Write("World"); | ||||||
|  |  | ||||||
|             // Move the cursor 5 cells to the left. |         // Move the cursor 5 cells to the left. | ||||||
|             AnsiConsole.Cursor.Move(CursorDirection.Left, 5); |         AnsiConsole.Cursor.Move(CursorDirection.Left, 5); | ||||||
|             AnsiConsole.WriteLine("Universe"); |         AnsiConsole.WriteLine("Universe"); | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -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 |         // Show a remapped emoji | ||||||
|             Emoji.Remap("globe_showing_europe_africa", Emoji.Known.GrinningFaceWithSmilingEyes); |         Emoji.Remap("globe_showing_europe_africa", Emoji.Known.GrinningFaceWithSmilingEyes); | ||||||
|             RenderEmoji(); |         RenderEmoji(); | ||||||
|         } |     } | ||||||
|  |  | ||||||
|         private static void RenderEmoji() |     private static void RenderEmoji() | ||||||
|         { |     { | ||||||
|             AnsiConsole.Write( |         AnsiConsole.Write( | ||||||
|                 new Panel("[yellow]Hello :globe_showing_europe_africa:![/]") |             new Panel("[yellow]Hello :globe_showing_europe_africa:![/]") | ||||||
|                     .RoundedBorder()); |                 .RoundedBorder()); | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,65 +1,64 @@ | |||||||
| using System; | using System; | ||||||
| using System.Security.Authentication; | 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); | ||||||
|             { |         } | ||||||
|                 DoMagic(42, null); |         catch (Exception ex) | ||||||
|             } |         { | ||||||
|             catch (Exception ex) |             AnsiConsole.WriteLine(); | ||||||
|             { |             AnsiConsole.Write(new Rule("Default").LeftAligned()); | ||||||
|                 AnsiConsole.WriteLine(); |             AnsiConsole.WriteLine(); | ||||||
|                 AnsiConsole.Write(new Rule("Default").LeftAligned()); |             AnsiConsole.WriteException(ex); | ||||||
|                 AnsiConsole.WriteLine(); |  | ||||||
|                 AnsiConsole.WriteException(ex); |  | ||||||
|  |  | ||||||
|                 AnsiConsole.WriteLine(); |             AnsiConsole.WriteLine(); | ||||||
|                 AnsiConsole.Write(new Rule("Compact").LeftAligned()); |             AnsiConsole.Write(new Rule("Compact").LeftAligned()); | ||||||
|                 AnsiConsole.WriteLine(); |             AnsiConsole.WriteLine(); | ||||||
|                 AnsiConsole.WriteException(ex, ExceptionFormats.ShortenEverything | ExceptionFormats.ShowLinks); |             AnsiConsole.WriteException(ex, ExceptionFormats.ShortenEverything | ExceptionFormats.ShowLinks); | ||||||
|  |  | ||||||
|                 AnsiConsole.WriteLine(); |             AnsiConsole.WriteLine(); | ||||||
|                 AnsiConsole.Write(new Rule("Compact + Custom colors").LeftAligned()); |             AnsiConsole.Write(new Rule("Compact + Custom colors").LeftAligned()); | ||||||
|                 AnsiConsole.WriteLine(); |             AnsiConsole.WriteLine(); | ||||||
|                 AnsiConsole.WriteException(ex, new ExceptionSettings |             AnsiConsole.WriteException(ex, new ExceptionSettings | ||||||
|  |             { | ||||||
|  |                 Format = ExceptionFormats.ShortenEverything | ExceptionFormats.ShowLinks, | ||||||
|  |                 Style = new ExceptionStyle | ||||||
|                 { |                 { | ||||||
|                     Format = ExceptionFormats.ShortenEverything | ExceptionFormats.ShowLinks, |                     Exception = new Style().Foreground(Color.Grey), | ||||||
|                     Style = new ExceptionStyle |                     Message = new Style().Foreground(Color.White), | ||||||
|                     { |                     NonEmphasized = new Style().Foreground(Color.Cornsilk1), | ||||||
|                         Exception = new Style().Foreground(Color.Grey), |                     Parenthesis = new Style().Foreground(Color.Cornsilk1), | ||||||
|                         Message = new Style().Foreground(Color.White), |                     Method = new Style().Foreground(Color.Red), | ||||||
|                         NonEmphasized = new Style().Foreground(Color.Cornsilk1), |                     ParameterName = new Style().Foreground(Color.Cornsilk1), | ||||||
|                         Parenthesis = new Style().Foreground(Color.Cornsilk1), |                     ParameterType = new Style().Foreground(Color.Red), | ||||||
|                         Method = new Style().Foreground(Color.Red), |                     Path = new Style().Foreground(Color.Red), | ||||||
|                         ParameterName = new Style().Foreground(Color.Cornsilk1), |                     LineNumber = 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."); |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     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."); | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -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("Left aligned").LeftAligned().Color(Color.Red)); |         AnsiConsole.Write(new FigletText("Right aligned").RightAligned().Color(Color.Blue)); | ||||||
|             AnsiConsole.Write(new FigletText("Centered").Centered().Color(Color.Green)); |  | ||||||
|             AnsiConsole.Write(new FigletText("Right aligned").RightAligned().Color(Color.Blue)); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -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]] [[[[--]] <additional arguments>...]]]][/]"); | ||||||
|             AnsiConsole.WriteLine(); |         AnsiConsole.WriteLine(); | ||||||
|             AnsiConsole.MarkupLine("Usage: [grey]dotnet [blue]run[/] [[options]] [[[[--]] <additional arguments>...]]]][/]"); |  | ||||||
|             AnsiConsole.WriteLine(); |  | ||||||
|  |  | ||||||
|             var grid = new Grid(); |         var grid = new Grid(); | ||||||
|             grid.AddColumn(new GridColumn().NoWrap()); |         grid.AddColumn(new GridColumn().NoWrap()); | ||||||
|             grid.AddColumn(new GridColumn().PadLeft(2)); |         grid.AddColumn(new GridColumn().PadLeft(2)); | ||||||
|             grid.AddRow("Options:"); |         grid.AddRow("Options:"); | ||||||
|             grid.AddRow("  [blue]-h[/], [blue]--help[/]", "Show command line help."); |         grid.AddRow("  [blue]-h[/], [blue]--help[/]", "Show command line help."); | ||||||
|             grid.AddRow("  [blue]-c[/], [blue]--configuration[/] <CONFIGURATION>", "The configuration to run for."); |         grid.AddRow("  [blue]-c[/], [blue]--configuration[/] <CONFIGURATION>", "The configuration to run for."); | ||||||
|             grid.AddRow("  [blue]-v[/], [blue]--verbosity[/] <LEVEL>", "Set the [grey]MSBuild[/] verbosity level."); |         grid.AddRow("  [blue]-v[/], [blue]--verbosity[/] <LEVEL>", "Set the [grey]MSBuild[/] verbosity level."); | ||||||
|  |  | ||||||
|             AnsiConsole.Write(grid); |         AnsiConsole.Write(grid); | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -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)) | ||||||
|             var grid = new Grid() |             .AddColumn() | ||||||
|                 .AddColumn(new GridColumn().NoWrap().PadRight(4)) |             .AddRow("[b]Enrichers[/]", string.Join(", ", AnsiConsole.Profile.Enrichers)) | ||||||
|                 .AddColumn() |             .AddRow("[b]Color system[/]", $"{AnsiConsole.Profile.Capabilities.ColorSystem}") | ||||||
|                 .AddRow("[b]Enrichers[/]", string.Join(", ", AnsiConsole.Profile.Enrichers)) |             .AddRow("[b]Unicode?[/]", $"{YesNo(AnsiConsole.Profile.Capabilities.Unicode)}") | ||||||
|                 .AddRow("[b]Color system[/]", $"{AnsiConsole.Profile.Capabilities.ColorSystem}") |             .AddRow("[b]Supports ansi?[/]", $"{YesNo(AnsiConsole.Profile.Capabilities.Ansi)}") | ||||||
|                 .AddRow("[b]Unicode?[/]", $"{YesNo(AnsiConsole.Profile.Capabilities.Unicode)}") |             .AddRow("[b]Supports links?[/]", $"{YesNo(AnsiConsole.Profile.Capabilities.Links)}") | ||||||
|                 .AddRow("[b]Supports ansi?[/]", $"{YesNo(AnsiConsole.Profile.Capabilities.Ansi)}") |             .AddRow("[b]Legacy console?[/]", $"{YesNo(AnsiConsole.Profile.Capabilities.Legacy)}") | ||||||
|                 .AddRow("[b]Supports links?[/]", $"{YesNo(AnsiConsole.Profile.Capabilities.Links)}") |             .AddRow("[b]Interactive?[/]", $"{YesNo(AnsiConsole.Profile.Capabilities.Interactive)}") | ||||||
|                 .AddRow("[b]Legacy console?[/]", $"{YesNo(AnsiConsole.Profile.Capabilities.Legacy)}") |             .AddRow("[b]Terminal?[/]", $"{YesNo(AnsiConsole.Profile.Out.IsTerminal)}") | ||||||
|                 .AddRow("[b]Interactive?[/]", $"{YesNo(AnsiConsole.Profile.Capabilities.Interactive)}") |             .AddRow("[b]Buffer width[/]", $"{AnsiConsole.Console.Profile.Width}") | ||||||
|                 .AddRow("[b]Terminal?[/]", $"{YesNo(AnsiConsole.Profile.Out.IsTerminal)}") |             .AddRow("[b]Buffer height[/]", $"{AnsiConsole.Console.Profile.Height}") | ||||||
|                 .AddRow("[b]Buffer width[/]", $"{AnsiConsole.Console.Profile.Width}") |             .AddRow("[b]Encoding[/]", $"{AnsiConsole.Console.Profile.Encoding.EncodingName}"); | ||||||
|                 .AddRow("[b]Buffer height[/]", $"{AnsiConsole.Console.Profile.Height}") |  | ||||||
|                 .AddRow("[b]Encoding[/]", $"{AnsiConsole.Console.Profile.Encoding.EncodingName}"); |  | ||||||
|  |  | ||||||
|             AnsiConsole.Write( |         AnsiConsole.Write( | ||||||
|                 new Panel(grid) |             new Panel(grid) | ||||||
|                     .Header("Information")); |                 .Header("Information")); | ||||||
|         } |     } | ||||||
|  |  | ||||||
|         private static string YesNo(bool value) |     private static string YesNo(bool value) | ||||||
|         { |     { | ||||||
|             return value ? "Yes" : "No"; |         return value ? "Yes" : "No"; | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -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[/]!"); | ||||||
|             { |         } | ||||||
|                 AnsiConsole.MarkupLine("[link=https://patriksvensson.se]Click to visit my blog[/]!"); |         else | ||||||
|             } |         { | ||||||
|             else |             AnsiConsole.MarkupLine("[red]It looks like your terminal doesn't support links[/]"); | ||||||
|             { |             AnsiConsole.WriteLine(); | ||||||
|                 AnsiConsole.MarkupLine("[red]It looks like your terminal doesn't support links[/]"); |             AnsiConsole.MarkupLine("[yellow](╯°□°)╯[/]︵ [blue]┻━┻[/]"); | ||||||
|                 AnsiConsole.WriteLine(); |  | ||||||
|                 AnsiConsole.MarkupLine("[yellow](╯°□°)╯[/]︵ [blue]┻━┻[/]"); |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,81 +1,80 @@ | |||||||
| using System; | using System; | ||||||
| using System.Threading; | using System.Threading; | ||||||
|  |  | ||||||
| namespace Spectre.Console.Examples | namespace Spectre.Console.Examples; | ||||||
| { |  | ||||||
|     public static class Program |  | ||||||
|     { |  | ||||||
|         public static void Main() |  | ||||||
|         { |  | ||||||
|             var table = new Table().Centered(); |  | ||||||
|  |  | ||||||
|             // Animate | public static class Program | ||||||
|             AnsiConsole.Live(table) | { | ||||||
|                 .AutoClear(false) |     public static void Main() | ||||||
|                 .Overflow(VerticalOverflow.Ellipsis) |     { | ||||||
|                 .Cropping(VerticalOverflowCropping.Top) |         var table = new Table().Centered(); | ||||||
|                 .Start(ctx => |  | ||||||
|  |         // 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(); | ||||||
|                         action(); |                     Thread.Sleep(delay); | ||||||
|                         ctx.Refresh(); |                 } | ||||||
|                         Thread.Sleep(delay); |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                     // Columns |                     // Columns | ||||||
|                     Update(230, () => table.AddColumn("Release date")); |                     Update(230, () => table.AddColumn("Release date")); | ||||||
|                     Update(230, () => table.AddColumn("Title")); |                 Update(230, () => table.AddColumn("Title")); | ||||||
|                     Update(230, () => table.AddColumn("Budget")); |                 Update(230, () => table.AddColumn("Budget")); | ||||||
|                     Update(230, () => table.AddColumn("Opening Weekend")); |                 Update(230, () => table.AddColumn("Opening Weekend")); | ||||||
|                     Update(230, () => table.AddColumn("Box office")); |                 Update(230, () => table.AddColumn("Box office")); | ||||||
|  |  | ||||||
|                     // Rows |                     // 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 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 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 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 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 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("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 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 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("Dec 20, 2019", "[yellow]Star Wars[/] [grey]Ep.[/] [u]IX[/]", "$245,000,000", "$177,383,864", "$1,074,114,248")); | ||||||
|  |  | ||||||
|                     // Column footer |                     // Column footer | ||||||
|                     Update(230, () => table.Columns[2].Footer("$1,633,000,000")); |                     Update(230, () => table.Columns[2].Footer("$1,633,000,000")); | ||||||
|                     Update(230, () => table.Columns[3].Footer("$928,119,224")); |                 Update(230, () => table.Columns[3].Footer("$928,119,224")); | ||||||
|                     Update(400, () => table.Columns[4].Footer("$10,318,030,576")); |                 Update(400, () => table.Columns[4].Footer("$10,318,030,576")); | ||||||
|  |  | ||||||
|                     // Column alignment |                     // Column alignment | ||||||
|                     Update(230, () => table.Columns[2].RightAligned()); |                     Update(230, () => table.Columns[2].RightAligned()); | ||||||
|                     Update(230, () => table.Columns[3].RightAligned()); |                 Update(230, () => table.Columns[3].RightAligned()); | ||||||
|                     Update(400, () => table.Columns[4].RightAligned()); |                 Update(400, () => table.Columns[4].RightAligned()); | ||||||
|  |  | ||||||
|                     // Column titles |                     // Column titles | ||||||
|                     Update(70, () => table.Columns[0].Header("[bold]Release date[/]")); |                     Update(70, () => table.Columns[0].Header("[bold]Release date[/]")); | ||||||
|                     Update(70, () => table.Columns[1].Header("[bold]Title[/]")); |                 Update(70, () => table.Columns[1].Header("[bold]Title[/]")); | ||||||
|                     Update(70, () => table.Columns[2].Header("[red bold]Budget[/]")); |                 Update(70, () => table.Columns[2].Header("[red bold]Budget[/]")); | ||||||
|                     Update(70, () => table.Columns[3].Header("[green bold]Opening Weekend[/]")); |                 Update(70, () => table.Columns[3].Header("[green bold]Opening Weekend[/]")); | ||||||
|                     Update(400, () => table.Columns[4].Header("[blue bold]Box office[/]")); |                 Update(400, () => table.Columns[4].Header("[blue bold]Box office[/]")); | ||||||
|  |  | ||||||
|                     // Footers |                     // Footers | ||||||
|                     Update(70, () => table.Columns[2].Footer("[red bold]$1,633,000,000[/]")); |                     Update(70, () => table.Columns[2].Footer("[red bold]$1,633,000,000[/]")); | ||||||
|                     Update(70, () => table.Columns[3].Footer("[green bold]$928,119,224[/]")); |                 Update(70, () => table.Columns[3].Footer("[green bold]$928,119,224[/]")); | ||||||
|                     Update(400, () => table.Columns[4].Footer("[blue bold]$10,318,030,576[/]")); |                 Update(400, () => table.Columns[4].Footer("[blue bold]$10,318,030,576[/]")); | ||||||
|  |  | ||||||
|                     // Title |                     // Title | ||||||
|                     Update(500, () => table.Title("Star Wars Movies")); |                     Update(500, () => table.Title("Star Wars Movies")); | ||||||
|                     Update(400, () => table.Title("[[ [yellow]Star Wars Movies[/] ]]")); |                 Update(400, () => table.Title("[[ [yellow]Star Wars Movies[/] ]]")); | ||||||
|  |  | ||||||
|                     // Borders |                     // Borders | ||||||
|                     Update(230, () => table.BorderColor(Color.Yellow)); |                     Update(230, () => table.BorderColor(Color.Yellow)); | ||||||
|                     Update(230, () => table.MinimalBorder()); |                 Update(230, () => table.MinimalBorder()); | ||||||
|                     Update(230, () => table.SimpleBorder()); |                 Update(230, () => table.SimpleBorder()); | ||||||
|                     Update(230, () => table.SimpleHeavyBorder()); |                 Update(230, () => table.SimpleHeavyBorder()); | ||||||
|  |  | ||||||
|                     // Caption |                     // Caption | ||||||
|                     Update(400, () => table.Caption("[[ [blue]THE END[/] ]]")); |                     Update(400, () => table.Caption("[[ [blue]THE END[/] ]]")); | ||||||
|                 }); |             }); | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -2,15 +2,15 @@ using System; | |||||||
| using System.Linq; | using System.Linq; | ||||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||||
|  |  | ||||||
| namespace Spectre.Console.Examples | namespace Spectre.Console.Examples; | ||||||
| { |  | ||||||
|     public static class Program |  | ||||||
|     { |  | ||||||
|         private const int NumberOfRows = 10; |  | ||||||
|  |  | ||||||
|         private static readonly Random _random = new(); | public static class Program | ||||||
|         private static readonly string[] _exchanges = new string[] | { | ||||||
|         { |     private const int NumberOfRows = 10; | ||||||
|  |  | ||||||
|  |     private static readonly Random _random = new(); | ||||||
|  |     private static readonly string[] _exchanges = new string[] | ||||||
|  |     { | ||||||
|             "SGD", "SEK", "PLN", |             "SGD", "SEK", "PLN", | ||||||
|             "MYR", "EUR", "USD", |             "MYR", "EUR", "USD", | ||||||
|             "AUD", "JPY", "CNH", |             "AUD", "JPY", "CNH", | ||||||
| @@ -18,69 +18,68 @@ namespace Spectre.Console.Examples | |||||||
|             "DKK", "GBP", "RUB", |             "DKK", "GBP", "RUB", | ||||||
|             "NZD", "MXN", "IDR", |             "NZD", "MXN", "IDR", | ||||||
|             "TWD", "THB", "VND", |             "TWD", "THB", "VND", | ||||||
|         }; |     }; | ||||||
|  |  | ||||||
|         public static async Task Main(string[] args) |     public static async Task Main(string[] args) | ||||||
|         { |     { | ||||||
|             var table = new Table().Expand().BorderColor(Color.Grey); |         var table = new Table().Expand().BorderColor(Color.Grey); | ||||||
|             table.AddColumn("[yellow]Source currency[/]"); |         table.AddColumn("[yellow]Source currency[/]"); | ||||||
|             table.AddColumn("[yellow]Destination currency[/]"); |         table.AddColumn("[yellow]Destination currency[/]"); | ||||||
|             table.AddColumn("[yellow]Exchange rate[/]"); |         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) |         await AnsiConsole.Live(table) | ||||||
|                 .AutoClear(false) |             .AutoClear(false) | ||||||
|                 .Overflow(VerticalOverflow.Ellipsis) |             .Overflow(VerticalOverflow.Ellipsis) | ||||||
|                 .Cropping(VerticalOverflowCropping.Bottom) |             .Cropping(VerticalOverflowCropping.Bottom) | ||||||
|                 .StartAsync(async ctx => |             .StartAsync(async ctx => | ||||||
|                 { |             { | ||||||
|                     // Add some initial rows |                     // Add some initial rows | ||||||
|                     foreach (var _ in Enumerable.Range(0, NumberOfRows)) |                     foreach (var _ in Enumerable.Range(0, NumberOfRows)) | ||||||
|                     { |                 { | ||||||
|                         AddExchangeRateRow(table); |                     AddExchangeRateRow(table); | ||||||
|                     } |                 } | ||||||
|  |  | ||||||
|                     // Continously update the table |                     // Continously update the table | ||||||
|                     while (true) |                     while (true) | ||||||
|                     { |                 { | ||||||
|                         // More rows than we want? |                         // More rows than we want? | ||||||
|                         if (table.Rows.Count > NumberOfRows) |                         if (table.Rows.Count > NumberOfRows) | ||||||
|                         { |                     { | ||||||
|                             // Remove the first one |                             // Remove the first one | ||||||
|                             table.Rows.RemoveAt(0); |                             table.Rows.RemoveAt(0); | ||||||
|                         } |                     } | ||||||
|  |  | ||||||
|                         // Add a new row |                         // Add a new row | ||||||
|                         AddExchangeRateRow(table); |                         AddExchangeRateRow(table); | ||||||
|  |  | ||||||
|                         // Refresh and wait for a while |                         // Refresh and wait for a while | ||||||
|                         ctx.Refresh(); |                         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(); |             dest = _exchanges[_random.Next(0, _exchanges.Length)]; | ||||||
|             table.AddRow( |  | ||||||
|                 source, destination, |  | ||||||
|                 _random.NextDouble() > 0.35D ? $"[green]{rate}[/]" : $"[red]{rate}[/]"); |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         private static (string Source, string Destination, double Rate) GetExchangeRate() |         return (source, dest, rate); | ||||||
|         { |  | ||||||
|             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); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -9,5 +9,4 @@ Write(new Table() | |||||||
|     .RoundedBorder() |     .RoundedBorder() | ||||||
|     .AddColumns("[red]Greeting[/]", "[red]Subject[/]") |     .AddColumns("[red]Greeting[/]", "[red]Subject[/]") | ||||||
|     .AddRow("[yellow]Hello[/]", "World") |     .AddRow("[yellow]Hello[/]", "World") | ||||||
|     .AddRow("[green]Oh hi[/]", "[blue u]Mark[/]")); |     .AddRow("[green]Oh hi[/]", "[blue u]Mark[/]")); | ||||||
|  |  | ||||||
| @@ -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" + | ||||||
|             var content = new Markup( |             "So I put a panel in a panel").Centered(); | ||||||
|                 "[underline]I[/] heard [underline on blue]you[/] like panels\n\n\n\n" + |  | ||||||
|                 "So I put a panel in a panel").Centered(); |  | ||||||
|  |  | ||||||
|             AnsiConsole.Write( |         AnsiConsole.Write( | ||||||
|                 new Panel( |             new Panel( | ||||||
|                     new Panel(content) |                 new Panel(content) | ||||||
|                         .Border(BoxBorder.Rounded))); |                     .Border(BoxBorder.Rounded))); | ||||||
|  |  | ||||||
|             // Left adjusted panel with text |         // Left adjusted panel with text | ||||||
|             AnsiConsole.Write( |         AnsiConsole.Write( | ||||||
|                 new Panel(new Text("Left adjusted\nLeft").LeftAligned()) |             new Panel(new Text("Left adjusted\nLeft").LeftAligned()) | ||||||
|                     .Expand() |                 .Expand() | ||||||
|                     .SquareBorder() |                 .SquareBorder() | ||||||
|                     .Header("[red]Left[/]")); |                 .Header("[red]Left[/]")); | ||||||
|  |  | ||||||
|             // Centered ASCII panel with text |         // Centered ASCII panel with text | ||||||
|             AnsiConsole.Write( |         AnsiConsole.Write( | ||||||
|                 new Panel(new Text("Centered\nCenter").Centered()) |             new Panel(new Text("Centered\nCenter").Centered()) | ||||||
|                     .Expand() |                 .Expand() | ||||||
|                     .AsciiBorder() |                 .AsciiBorder() | ||||||
|                     .Header("[green]Center[/]") |                 .Header("[green]Center[/]") | ||||||
|                     .HeaderAlignment(Justify.Center)); |                 .HeaderAlignment(Justify.Center)); | ||||||
|  |  | ||||||
|             // Right adjusted, rounded panel with text |         // Right adjusted, rounded panel with text | ||||||
|             AnsiConsole.Write( |         AnsiConsole.Write( | ||||||
|                 new Panel(new Text("Right adjusted\nRight").RightAligned()) |             new Panel(new Text("Right adjusted\nRight").RightAligned()) | ||||||
|                     .Expand() |                 .Expand() | ||||||
|                     .RoundedBorder() |                 .RoundedBorder() | ||||||
|                     .Header("[blue]Right[/]") |                 .Header("[blue]Right[/]") | ||||||
|                     .HeaderAlignment(Justify.Right)); |                 .HeaderAlignment(Justify.Right)); | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,45 +1,44 @@ | |||||||
| using System; | using System; | ||||||
| using System.Collections.Generic; | 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<string> _used; | ||||||
|  |  | ||||||
|  |     static DescriptionGenerator() | ||||||
|     { |     { | ||||||
|         private static readonly string[] _verbs = new[] { "Downloading", "Rerouting", "Retriculating", "Collapsing", "Folding", "Solving", "Colliding", "Measuring" }; |         _random = new Random(DateTime.Now.Millisecond); | ||||||
|         private static readonly string[] _nouns = new[] { "internet", "splines", "space", "capacitators", "quarks", "algorithms", "data structures", "spacetime" }; |         _used = new HashSet<string>(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|         private static readonly Random _random; |     public static bool TryGenerate(out string name) | ||||||
|         private static readonly HashSet<string> _used; |     { | ||||||
|  |         var iterations = 0; | ||||||
|         static DescriptionGenerator() |         while (iterations < 25) | ||||||
|         { |         { | ||||||
|             _random = new Random(DateTime.Now.Millisecond); |             name = Generate(); | ||||||
|             _used = new HashSet<string>(); |             if (!_used.Contains(name)) | ||||||
|         } |  | ||||||
|  |  | ||||||
|         public static bool TryGenerate(out string name) |  | ||||||
|         { |  | ||||||
|             var iterations = 0; |  | ||||||
|             while (iterations < 25) |  | ||||||
|             { |             { | ||||||
|                 name = Generate(); |                 _used.Add(name); | ||||||
|                 if (!_used.Contains(name)) |                 return true; | ||||||
|                 { |  | ||||||
|                     _used.Add(name); |  | ||||||
|                     return true; |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 iterations++; |  | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             name = Generate(); |             iterations++; | ||||||
|             return false; |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         public static string Generate() |         name = Generate(); | ||||||
|         { |         return false; | ||||||
|             return _verbs[_random.Next(0, _verbs.Length)] |     } | ||||||
|                 + " " + _nouns[_random.Next(0, _nouns.Length)]; |  | ||||||
|         } |     public static string Generate() | ||||||
|  |     { | ||||||
|  |         return _verbs[_random.Next(0, _verbs.Length)] | ||||||
|  |             + " " + _nouns[_random.Next(0, _nouns.Length)]; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -2,88 +2,87 @@ using System; | |||||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||||
| using System.Threading; | using System.Threading; | ||||||
|  |  | ||||||
| namespace Spectre.Console.Examples | namespace Spectre.Console.Examples; | ||||||
| { |  | ||||||
|     public static class Program |  | ||||||
|     { |  | ||||||
|         public static void Main() |  | ||||||
|         { |  | ||||||
|             AnsiConsole.MarkupLine("[yellow]Initializing warp drive[/]..."); |  | ||||||
|  |  | ||||||
|             // Show progress | public static class Program | ||||||
|             AnsiConsole.Progress() | { | ||||||
|                 .AutoClear(false) |     public static void Main() | ||||||
|                 .Columns(new ProgressColumn[] |     { | ||||||
|                 { |         AnsiConsole.MarkupLine("[yellow]Initializing warp drive[/]..."); | ||||||
|  |  | ||||||
|  |         // Show progress | ||||||
|  |         AnsiConsole.Progress() | ||||||
|  |             .AutoClear(false) | ||||||
|  |             .Columns(new ProgressColumn[] | ||||||
|  |             { | ||||||
|                     new TaskDescriptionColumn(),    // Task description |                     new TaskDescriptionColumn(),    // Task description | ||||||
|                     new ProgressBarColumn(),        // Progress bar |                     new ProgressBarColumn(),        // Progress bar | ||||||
|                     new PercentageColumn(),         // Percentage |                     new PercentageColumn(),         // Percentage | ||||||
|                     new RemainingTimeColumn(),      // Remaining time |                     new RemainingTimeColumn(),      // Remaining time | ||||||
|                     new SpinnerColumn(),            // Spinner |                     new SpinnerColumn(),            // Spinner | ||||||
|                 }) |             }) | ||||||
|                 .Start(ctx => |             .Start(ctx => | ||||||
|                 { |             { | ||||||
|                     var random = new Random(DateTime.Now.Millisecond); |                 var random = new Random(DateTime.Now.Millisecond); | ||||||
|  |  | ||||||
|                     // Create some tasks |                     // Create some tasks | ||||||
|                     var tasks = CreateTasks(ctx, random); |                     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 |                     // Wait for all tasks (except the indeterminate one) to complete | ||||||
|                     while (!ctx.IsFinished) |                     while (!ctx.IsFinished) | ||||||
|                     { |                 { | ||||||
|                         // Increment progress |                         // Increment progress | ||||||
|                         foreach (var (task, increment) in tasks) |                         foreach (var (task, increment) in tasks) | ||||||
|                         { |                     { | ||||||
|                             task.Increment(random.NextDouble() * increment); |                         task.Increment(random.NextDouble() * increment); | ||||||
|                         } |                     } | ||||||
|  |  | ||||||
|                         // Write some random things to the terminal |                         // Write some random things to the terminal | ||||||
|                         if (random.NextDouble() < 0.1) |                         if (random.NextDouble() < 0.1) | ||||||
|                         { |                     { | ||||||
|                             WriteLogMessage(); |                         WriteLogMessage(); | ||||||
|                         } |                     } | ||||||
|  |  | ||||||
|                         // Simulate some delay |                         // Simulate some delay | ||||||
|                         Thread.Sleep(100); |                         Thread.Sleep(100); | ||||||
|                     } |                 } | ||||||
|  |  | ||||||
|                     // Now start the "warp" task |                     // Now start the "warp" task | ||||||
|                     warpTask.StartTask(); |                     warpTask.StartTask(); | ||||||
|                     warpTask.IsIndeterminate(false); |                 warpTask.IsIndeterminate(false); | ||||||
|                     while (!ctx.IsFinished) |                 while (!ctx.IsFinished) | ||||||
|                     { |                 { | ||||||
|                         warpTask.Increment(12 * random.NextDouble()); |                     warpTask.Increment(12 * random.NextDouble()); | ||||||
|  |  | ||||||
|                         // Simulate some delay |                         // Simulate some delay | ||||||
|                         Thread.Sleep(100); |                         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( |             if (DescriptionGenerator.TryGenerate(out var name)) | ||||||
|                 "[grey]LOG:[/] " + |             { | ||||||
|                 DescriptionGenerator.Generate() + |                 tasks.Add((progress.AddTask(name), random.Next(2, 10))); | ||||||
|                 "[grey]...[/]"); |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         return tasks; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private static void WriteLogMessage() | ||||||
|  |     { | ||||||
|  |         AnsiConsole.MarkupLine( | ||||||
|  |             "[grey]LOG:[/] " + | ||||||
|  |             DescriptionGenerator.Generate() + | ||||||
|  |             "[grey]...[/]"); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -142,4 +142,4 @@ namespace Spectre.Console.Examples | |||||||
|                     .AllowEmpty()); |                     .AllowEmpty()); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -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( | ||||||
|             // No title |             new Rule() | ||||||
|             Render( |                 .RuleStyle(Style.Parse("yellow")) | ||||||
|                 new Rule() |                 .AsciiBorder() | ||||||
|                     .RuleStyle(Style.Parse("yellow")) |                 .LeftAligned()); | ||||||
|                     .AsciiBorder() |  | ||||||
|                     .LeftAligned()); |  | ||||||
|  |  | ||||||
|             // Left aligned title |         // Left aligned title | ||||||
|             Render( |         Render( | ||||||
|                 new Rule("[blue]Left aligned[/]") |             new Rule("[blue]Left aligned[/]") | ||||||
|                     .RuleStyle(Style.Parse("red")) |                 .RuleStyle(Style.Parse("red")) | ||||||
|                     .DoubleBorder() |                 .DoubleBorder() | ||||||
|                     .LeftAligned()); |                 .LeftAligned()); | ||||||
|  |  | ||||||
|             // Centered title |         // Centered title | ||||||
|             Render( |         Render( | ||||||
|                 new Rule("[green]Centered[/]") |             new Rule("[green]Centered[/]") | ||||||
|                     .RuleStyle(Style.Parse("green")) |                 .RuleStyle(Style.Parse("green")) | ||||||
|                     .HeavyBorder() |                 .HeavyBorder() | ||||||
|                     .Centered()); |                 .Centered()); | ||||||
|  |  | ||||||
|             // Right aligned title |         // Right aligned title | ||||||
|             Render( |         Render( | ||||||
|                 new Rule("[red]Right aligned[/]") |             new Rule("[red]Right aligned[/]") | ||||||
|                     .RuleStyle(Style.Parse("blue")) |                 .RuleStyle(Style.Parse("blue")) | ||||||
|                     .RightAligned()); |                 .RightAligned()); | ||||||
|         } |     } | ||||||
|  |  | ||||||
|         private static void Render(Rule rule) |     private static void Render(Rule rule) | ||||||
|         { |     { | ||||||
|             AnsiConsole.Write(rule); |         AnsiConsole.Write(rule); | ||||||
|             AnsiConsole.WriteLine(); |         AnsiConsole.WriteLine(); | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,30 +1,29 @@ | |||||||
| using System; | 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(); | ||||||
|                 SomeOperation(); |  | ||||||
|                 throw new InvalidOperationException(); |  | ||||||
|             } |  | ||||||
|             catch (Exception ex) |  | ||||||
|             { |  | ||||||
|                 return ex; |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|  |         catch (Exception ex) | ||||||
|         private static void SomeOperation() |  | ||||||
|         { |         { | ||||||
|             SomeOperationGoingWrong(); |             return ex; | ||||||
|         } |  | ||||||
|  |  | ||||||
|         private static void SomeOperationGoingWrong() |  | ||||||
|         { |  | ||||||
|             throw new InvalidOperationException("Something went very wrong!"); |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     private static void SomeOperation() | ||||||
|  |     { | ||||||
|  |         SomeOperationGoingWrong(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private static void SomeOperationGoingWrong() | ||||||
|  |     { | ||||||
|  |         throw new InvalidOperationException("Something went very wrong!"); | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,153 +1,152 @@ | |||||||
| using Spectre.Console.Rendering; | 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[/][/]"); | ||||||
|             var table = new Table().HideHeaders().NoBorder(); |         table.AddColumn("Feature", c => c.NoWrap().RightAligned().Width(10).PadRight(3)); | ||||||
|             table.Title("[u][yellow]Spectre.Console[/] [b]Features[/][/]"); |         table.AddColumn("Demonstration", c => c.PadRight(0)); | ||||||
|             table.AddColumn("Feature", c => c.NoWrap().RightAligned().Width(10).PadRight(3)); |         table.AddEmptyRow(); | ||||||
|             table.AddColumn("Demonstration", c => c.PadRight(0)); |  | ||||||
|             table.AddEmptyRow(); |  | ||||||
|  |  | ||||||
|             // Colors |         // Colors | ||||||
|             table.AddRow( |         table.AddRow( | ||||||
|                 new Markup("[red]Colors[/]"), |             new Markup("[red]Colors[/]"), | ||||||
|                 GetColorTable()); |             GetColorTable()); | ||||||
|  |  | ||||||
|             // Styles |         // Styles | ||||||
|             table.AddEmptyRow(); |         table.AddEmptyRow(); | ||||||
|             table.AddRow( |         table.AddRow( | ||||||
|                 new Markup("[red]OS[/]"), |             new Markup("[red]OS[/]"), | ||||||
|                 new Grid().Expand().AddColumns(3) |             new Grid().Expand().AddColumns(3) | ||||||
|                 .AddRow( |             .AddRow( | ||||||
|                     "[bold green]Windows[/]", |                 "[bold green]Windows[/]", | ||||||
|                     "[bold blue]macOS[/]", |                 "[bold blue]macOS[/]", | ||||||
|                     "[bold yellow]Linux[/]")); |                 "[bold yellow]Linux[/]")); | ||||||
|  |  | ||||||
|             // Styles |         // Styles | ||||||
|             table.AddEmptyRow(); |         table.AddEmptyRow(); | ||||||
|             table.AddRow( |         table.AddRow( | ||||||
|                 "[red]Styles[/]", |             "[red]Styles[/]", | ||||||
|                 "All ansi styles: [bold]bold[/], [dim]dim[/], [italic]italic[/], [underline]underline[/], " |             "All ansi styles: [bold]bold[/], [dim]dim[/], [italic]italic[/], [underline]underline[/], " | ||||||
|                     + "[strikethrough]strikethrough[/], [reverse]reverse[/], and even [blink]blink[/]."); |                 + "[strikethrough]strikethrough[/], [reverse]reverse[/], and even [blink]blink[/]."); | ||||||
|  |  | ||||||
|             // Text |         // Text | ||||||
|             table.AddEmptyRow(); |         table.AddEmptyRow(); | ||||||
|             table.AddRow( |         table.AddRow( | ||||||
|                 new Markup("[red]Text[/]"), |             new Markup("[red]Text[/]"), | ||||||
|                 new Markup("Word wrap text. Justify [green]left[/], [yellow]center[/] or [blue]right[/].")); |             new Markup("Word wrap text. Justify [green]left[/], [yellow]center[/] or [blue]right[/].")); | ||||||
|  |  | ||||||
|             table.AddEmptyRow(); |         table.AddEmptyRow(); | ||||||
|             table.AddRow( |         table.AddRow( | ||||||
|                 Text.Empty, |             Text.Empty, | ||||||
|                 GetTextGrid()); |             GetTextGrid()); | ||||||
|  |  | ||||||
|             // Markup |         // Markup | ||||||
|             table.AddEmptyRow(); |         table.AddEmptyRow(); | ||||||
|             table.AddRow( |         table.AddRow( | ||||||
|                 "[red]Markup[/]", |             "[red]Markup[/]", | ||||||
|                 "[bold purple]Spectre.Console[/] supports a simple [i]bbcode[/] like " |             "[bold purple]Spectre.Console[/] supports a simple [i]bbcode[/] like " | ||||||
|                     + "[b]markup[/] for [yellow]color[/], [underline]style[/], and emoji! " |                 + "[b]markup[/] for [yellow]color[/], [underline]style[/], and emoji! " | ||||||
|                     + ":thumbs_up: :red_apple: :ant: :bear: :baguette_bread: :bus:"); |                 + ":thumbs_up: :red_apple: :ant: :bear: :baguette_bread: :bus:"); | ||||||
|  |  | ||||||
|             // Trees and tables |         // Trees and tables | ||||||
|             table.AddEmptyRow(); |         table.AddEmptyRow(); | ||||||
|             table.AddRow( |         table.AddRow( | ||||||
|                 new Markup("[red]Tables and Trees[/]"), |             new Markup("[red]Tables and Trees[/]"), | ||||||
|                 GetTreeTable()); |             GetTreeTable()); | ||||||
|  |  | ||||||
|             // Charts |         // Charts | ||||||
|             table.AddRow( |         table.AddRow( | ||||||
|                 new Markup("[red]Charts[/]"), |             new Markup("[red]Charts[/]"), | ||||||
|                 new Grid().Collapse().AddColumns(2).AddRow( |             new Grid().Collapse().AddColumns(2).AddRow( | ||||||
|                     new Panel(GetBreakdownChart()).BorderColor(Color.Grey), |                 new Panel(GetBreakdownChart()).BorderColor(Color.Grey), | ||||||
|                     new Panel(GetBarChart()).BorderColor(Color.Grey))); |                 new Panel(GetBarChart()).BorderColor(Color.Grey))); | ||||||
|  |  | ||||||
|  |  | ||||||
|             // Exceptions |         // Exceptions | ||||||
|             table.AddEmptyRow(); |         table.AddEmptyRow(); | ||||||
|             table.AddRow( |         table.AddRow( | ||||||
|                 new Markup("[red]Exceptions[/]"), |             new Markup("[red]Exceptions[/]"), | ||||||
|                 ExceptionGenerator.GenerateException().GetRenderable()); |             ExceptionGenerator.GenerateException().GetRenderable()); | ||||||
|  |  | ||||||
|             // Much more |         // Much more | ||||||
|             table.AddEmptyRow(); |         table.AddEmptyRow(); | ||||||
|             table.AddRow( |         table.AddRow( | ||||||
|                 "[red]+ Much more![/]", |             "[red]+ Much more![/]", | ||||||
|                 "Tables, Grids, Trees, Progress bars, Status, Bar charts, Calendars, Figlet, Images, Text prompts, " |             "Tables, Grids, Trees, Progress bars, Status, Bar charts, Calendars, Figlet, Images, Text prompts, " | ||||||
|                     + "List boxes, Separators, Pretty exceptions, Canvas, CLI parsing"); |                 + "List boxes, Separators, Pretty exceptions, Canvas, CLI parsing"); | ||||||
|             table.AddEmptyRow(); |         table.AddEmptyRow(); | ||||||
|  |  | ||||||
|             // Render the table |         // Render the table | ||||||
|             AnsiConsole.WriteLine(); |         AnsiConsole.WriteLine(); | ||||||
|             AnsiConsole.Write(table); |         AnsiConsole.Write(table); | ||||||
|         } |     } | ||||||
|  |  | ||||||
|         private static IRenderable GetColorTable() |     private static IRenderable GetColorTable() | ||||||
|         { |     { | ||||||
|             var colorTable = new Table().Collapse().HideHeaders().NoBorder(); |         var colorTable = new Table().Collapse().HideHeaders().NoBorder(); | ||||||
|             colorTable.AddColumn("Desc", c => c.PadRight(3)).AddColumn("Colors", c => c.PadRight(0)); |         colorTable.AddColumn("Desc", c => c.PadRight(3)).AddColumn("Colors", c => c.PadRight(0)); | ||||||
|             colorTable.AddRow( |         colorTable.AddRow( | ||||||
|                 new Markup( |             new Markup( | ||||||
|                     "✓ [bold grey]NO_COLOR support[/]\n" + |                 "✓ [bold grey]NO_COLOR support[/]\n" + | ||||||
|                     "✓ [bold green]3-bit color[/]\n" + |                 "✓ [bold green]3-bit color[/]\n" + | ||||||
|                     "✓ [bold blue]4-bit color[/]\n" + |                 "✓ [bold blue]4-bit color[/]\n" + | ||||||
|                     "✓ [bold purple]8-bit color[/]\n" + |                 "✓ [bold purple]8-bit color[/]\n" + | ||||||
|                     "✓ [bold yellow]Truecolor (16.7 million)[/]\n" + |                 "✓ [bold yellow]Truecolor (16.7 million)[/]\n" + | ||||||
|                     "✓ [bold aqua]Automatic color conversion[/]"), |                 "✓ [bold aqua]Automatic color conversion[/]"), | ||||||
|                 new ColorBox(height: 6)); |             new ColorBox(height: 6)); | ||||||
|  |  | ||||||
|             return colorTable; |         return colorTable; | ||||||
|         } |     } | ||||||
|  |  | ||||||
|         private static IRenderable GetTextGrid() |     private static IRenderable GetTextGrid() | ||||||
|         { |     { | ||||||
|             var loremTable = new Grid(); |         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."; |         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().LeftAligned()); | ||||||
|             loremTable.AddColumn(new GridColumn().Centered()); |         loremTable.AddColumn(new GridColumn().Centered()); | ||||||
|             loremTable.AddColumn(new GridColumn().RightAligned()); |         loremTable.AddColumn(new GridColumn().RightAligned()); | ||||||
|             loremTable.AddRow($"[green]{lorem}[/]", $"[yellow]{lorem}[/]", $"[blue]{lorem}[/]"); |         loremTable.AddRow($"[green]{lorem}[/]", $"[yellow]{lorem}[/]", $"[blue]{lorem}[/]"); | ||||||
|             return loremTable; |         return loremTable; | ||||||
|         } |     } | ||||||
|  |  | ||||||
|         private static IRenderable GetTreeTable() |     private static IRenderable GetTreeTable() | ||||||
|         { |     { | ||||||
|             var tree = new Tree("📁 src"); |         var tree = new Tree("📁 src"); | ||||||
|             tree.AddNode("📁 foo").AddNode("📄 bar.cs"); |         tree.AddNode("📁 foo").AddNode("📄 bar.cs"); | ||||||
|             tree.AddNode("📁 baz").AddNode("📁 qux").AddNode("📄 corgi.txt"); |         tree.AddNode("📁 baz").AddNode("📁 qux").AddNode("📄 corgi.txt"); | ||||||
|             tree.AddNode("📄 waldo.xml"); |         tree.AddNode("📄 waldo.xml"); | ||||||
|  |  | ||||||
|             var table = new Table().SimpleBorder().BorderColor(Color.Grey); |         var table = new Table().SimpleBorder().BorderColor(Color.Grey); | ||||||
|             table.AddColumn(new TableColumn("Overview")); |         table.AddColumn(new TableColumn("Overview")); | ||||||
|             table.AddColumn(new TableColumn("").Footer("[grey]3 Files, 225 KiB[/]")); |         table.AddColumn(new TableColumn("").Footer("[grey]3 Files, 225 KiB[/]")); | ||||||
|             table.AddRow(new Markup("[yellow]Files[/]"), tree); |         table.AddRow(new Markup("[yellow]Files[/]"), tree); | ||||||
|  |  | ||||||
|             return new Table().RoundedBorder().Collapse().BorderColor(Color.Yellow) |         return new Table().RoundedBorder().Collapse().BorderColor(Color.Yellow) | ||||||
|                 .AddColumn("Foo").AddColumn("Bar") |             .AddColumn("Foo").AddColumn("Bar") | ||||||
|                 .AddRow(new Text("Baz"), table) |             .AddRow(new Text("Baz"), table) | ||||||
|                 .AddRow("Qux", "Corgi"); |             .AddRow("Qux", "Corgi"); | ||||||
|         } |     } | ||||||
|  |  | ||||||
|         private static IRenderable GetBarChart() |     private static IRenderable GetBarChart() | ||||||
|         { |     { | ||||||
|             return new BarChart() |         return new BarChart() | ||||||
|                 .AddItem("Apple", 32, Color.Green) |             .AddItem("Apple", 32, Color.Green) | ||||||
|                 .AddItem("Oranges", 13, Color.Orange1) |             .AddItem("Oranges", 13, Color.Orange1) | ||||||
|                 .AddItem("Bananas", 22, Color.Yellow); |             .AddItem("Bananas", 22, Color.Yellow); | ||||||
|         } |     } | ||||||
|  |  | ||||||
|         private static IRenderable GetBreakdownChart() |     private static IRenderable GetBreakdownChart() | ||||||
|         { |     { | ||||||
|             return new BreakdownChart() |         return new BreakdownChart() | ||||||
|                 .ShowPercentage() |             .ShowPercentage() | ||||||
|                 .FullSize() |             .FullSize() | ||||||
|                 .AddItem("C#", 82, Color.Green) |             .AddItem("C#", 82, Color.Green) | ||||||
|                 .AddItem("PowerShell", 13, Color.Red) |             .AddItem("PowerShell", 13, Color.Red) | ||||||
|                 .AddItem("Bash", 5, Color.Blue); |             .AddItem("Bash", 5, Color.Blue); | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,69 +1,68 @@ | |||||||
| using System.Threading; | 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) | ||||||
|             AnsiConsole.Status() |             .Spinner(Spinner.Known.Default) | ||||||
|                 .AutoRefresh(true) |             .Start("[yellow]Initializing warp drive[/]", ctx => | ||||||
|                 .Spinner(Spinner.Known.Default) |             { | ||||||
|                 .Start("[yellow]Initializing warp drive[/]", ctx => |  | ||||||
|                 { |  | ||||||
|                     // Initialize |                     // Initialize | ||||||
|                     Thread.Sleep(3000); |                     Thread.Sleep(3000); | ||||||
|                     WriteLogMessage("Starting gravimetric field displacement manifold"); |                 WriteLogMessage("Starting gravimetric field displacement manifold"); | ||||||
|                     Thread.Sleep(1000); |                 Thread.Sleep(1000); | ||||||
|                     WriteLogMessage("Warming up deuterium chamber"); |                 WriteLogMessage("Warming up deuterium chamber"); | ||||||
|                     Thread.Sleep(2000); |                 Thread.Sleep(2000); | ||||||
|                     WriteLogMessage("Generating antideuterium"); |                 WriteLogMessage("Generating antideuterium"); | ||||||
|  |  | ||||||
|                     // Warp nacelles |                     // Warp nacelles | ||||||
|                     Thread.Sleep(3000); |                     Thread.Sleep(3000); | ||||||
|                     ctx.Spinner(Spinner.Known.BouncingBar); |                 ctx.Spinner(Spinner.Known.BouncingBar); | ||||||
|                     ctx.Status("[bold blue]Unfolding warp nacelles[/]"); |                 ctx.Status("[bold blue]Unfolding warp nacelles[/]"); | ||||||
|                     WriteLogMessage("Unfolding left warp nacelle"); |                 WriteLogMessage("Unfolding left warp nacelle"); | ||||||
|                     Thread.Sleep(2000); |                 Thread.Sleep(2000); | ||||||
|                     WriteLogMessage("Left warp nacelle [green]online[/]"); |                 WriteLogMessage("Left warp nacelle [green]online[/]"); | ||||||
|                     WriteLogMessage("Unfolding right warp nacelle"); |                 WriteLogMessage("Unfolding right warp nacelle"); | ||||||
|                     Thread.Sleep(1000); |                 Thread.Sleep(1000); | ||||||
|                     WriteLogMessage("Right warp nacelle [green]online[/]"); |                 WriteLogMessage("Right warp nacelle [green]online[/]"); | ||||||
|  |  | ||||||
|                     // Warp bubble |                     // Warp bubble | ||||||
|                     Thread.Sleep(3000); |                     Thread.Sleep(3000); | ||||||
|                     ctx.Spinner(Spinner.Known.Star2); |                 ctx.Spinner(Spinner.Known.Star2); | ||||||
|                     ctx.Status("[bold blue]Generating warp bubble[/]"); |                 ctx.Status("[bold blue]Generating warp bubble[/]"); | ||||||
|                     Thread.Sleep(3000); |                 Thread.Sleep(3000); | ||||||
|                     ctx.Spinner(Spinner.Known.Star); |                 ctx.Spinner(Spinner.Known.Star); | ||||||
|                     ctx.Status("[bold blue]Stabilizing warp bubble[/]"); |                 ctx.Status("[bold blue]Stabilizing warp bubble[/]"); | ||||||
|  |  | ||||||
|                     // Safety |                     // Safety | ||||||
|                     ctx.Spinner(Spinner.Known.Monkey); |                     ctx.Spinner(Spinner.Known.Monkey); | ||||||
|                     ctx.Status("[bold blue]Performing safety checks[/]"); |                 ctx.Status("[bold blue]Performing safety checks[/]"); | ||||||
|                     WriteLogMessage("Enabling interior dampening"); |                 WriteLogMessage("Enabling interior dampening"); | ||||||
|                     Thread.Sleep(2000); |                 Thread.Sleep(2000); | ||||||
|                     WriteLogMessage("Interior dampening [green]enabled[/]"); |                 WriteLogMessage("Interior dampening [green]enabled[/]"); | ||||||
|  |  | ||||||
|                     // Warp! |                     // Warp! | ||||||
|                     Thread.Sleep(3000); |                     Thread.Sleep(3000); | ||||||
|                     ctx.Spinner(Spinner.Known.Moon); |                 ctx.Spinner(Spinner.Known.Moon); | ||||||
|                     WriteLogMessage("Preparing for warp"); |                 WriteLogMessage("Preparing for warp"); | ||||||
|                     Thread.Sleep(1000); |                 Thread.Sleep(1000); | ||||||
|                     for (var warp = 1; warp < 10; warp++) |                 for (var warp = 1; warp < 10; warp++) | ||||||
|                     { |                 { | ||||||
|                         ctx.Status($"[bold blue]Warp {warp}[/]"); |                     ctx.Status($"[bold blue]Warp {warp}[/]"); | ||||||
|                         Thread.Sleep(500); |                     Thread.Sleep(500); | ||||||
|                     } |                 } | ||||||
|                 }); |             }); | ||||||
|  |  | ||||||
|             // Done |         // Done | ||||||
|             AnsiConsole.MarkupLine("[bold green]Crusing at Warp 9.8[/]"); |         AnsiConsole.MarkupLine("[bold green]Crusing at Warp 9.8[/]"); | ||||||
|         } |     } | ||||||
|  |  | ||||||
|         private static void WriteLogMessage(string message) |     private static void WriteLogMessage(string message) | ||||||
|         { |     { | ||||||
|             AnsiConsole.MarkupLine($"[grey]LOG:[/] {message}[grey]...[/]"); |         AnsiConsole.MarkupLine($"[grey]LOG:[/] {message}[grey]...[/]"); | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -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() |     private static Table CreateTable() | ||||||
|         { |     { | ||||||
|             var simple = new Table() |         var simple = new Table() | ||||||
|                 .Border(TableBorder.Square) |             .Border(TableBorder.Square) | ||||||
|                 .BorderColor(Color.Red) |             .BorderColor(Color.Red) | ||||||
|                 .AddColumn(new TableColumn("[u]CDE[/]").Footer("EDC").Centered()) |             .AddColumn(new TableColumn("[u]CDE[/]").Footer("EDC").Centered()) | ||||||
|                 .AddColumn(new TableColumn("[u]FED[/]").Footer("DEF")) |             .AddColumn(new TableColumn("[u]FED[/]").Footer("DEF")) | ||||||
|                 .AddColumn(new TableColumn("[u]IHG[/]").Footer("GHI")) |             .AddColumn(new TableColumn("[u]IHG[/]").Footer("GHI")) | ||||||
|                 .AddRow("Hello", "[red]World![/]", "") |             .AddRow("Hello", "[red]World![/]", "") | ||||||
|                 .AddRow("[blue]Bonjour[/]", "[white]le[/]", "[red]monde![/]") |             .AddRow("[blue]Bonjour[/]", "[white]le[/]", "[red]monde![/]") | ||||||
|                 .AddRow("[blue]Hej[/]", "[yellow]Världen![/]", ""); |             .AddRow("[blue]Hej[/]", "[yellow]Världen![/]", ""); | ||||||
|  |  | ||||||
|             var second = new Table() |         var second = new Table() | ||||||
|                 .Border(TableBorder.Rounded) |             .Border(TableBorder.Rounded) | ||||||
|                 .BorderColor(Color.Green) |             .BorderColor(Color.Green) | ||||||
|                 .AddColumn(new TableColumn("[u]Foo[/]")) |             .AddColumn(new TableColumn("[u]Foo[/]")) | ||||||
|                 .AddColumn(new TableColumn("[u]Bar[/]")) |             .AddColumn(new TableColumn("[u]Bar[/]")) | ||||||
|                 .AddColumn(new TableColumn("[u]Baz[/]")) |             .AddColumn(new TableColumn("[u]Baz[/]")) | ||||||
|                 .AddRow("Hello", "[red]World![/]", "") |             .AddRow("Hello", "[red]World![/]", "") | ||||||
|                 .AddRow(simple, new Text("Whaaat"), new Text("Lolz")) |             .AddRow(simple, new Text("Whaaat"), new Text("Lolz")) | ||||||
|                 .AddRow("[blue]Hej[/]", "[yellow]Världen![/]", ""); |             .AddRow("[blue]Hej[/]", "[yellow]Världen![/]", ""); | ||||||
|  |  | ||||||
|             return new Table() |         return new Table() | ||||||
|                 .Centered() |             .Centered() | ||||||
|                 .Border(TableBorder.DoubleEdge) |             .Border(TableBorder.DoubleEdge) | ||||||
|                 .Title("TABLE [yellow]TITLE[/]") |             .Title("TABLE [yellow]TITLE[/]") | ||||||
|                 .Caption("TABLE [yellow]CAPTION[/]") |             .Caption("TABLE [yellow]CAPTION[/]") | ||||||
|                 .AddColumn(new TableColumn(new Panel("[u]ABC[/]").BorderColor(Color.Red)).Footer("[u]FOOTER 1[/]")) |             .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]DEF[/]").BorderColor(Color.Green)).Footer("[u]FOOTER 2[/]")) | ||||||
|                 .AddColumn(new TableColumn(new Panel("[u]GHI[/]").BorderColor(Color.Blue)).Footer("[u]FOOTER 3[/]")) |             .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(new Text("Hello").Centered(), new Markup("[red]World![/]"), Text.Empty) | ||||||
|                 .AddRow(second, new Text("Whaaat"), new Text("Lol")) |             .AddRow(second, new Text("Whaaat"), new Text("Lol")) | ||||||
|                 .AddRow(new Markup("[blue]Hej[/]").Centered(), new Markup("[yellow]Världen![/]"), Text.Empty); |             .AddRow(new Markup("[blue]Hej[/]").Centered(), new Markup("[yellow]Världen![/]"), Text.Empty); | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -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 |         // Render the tree | ||||||
|             var tree = BuildTree(); |         var tree = BuildTree(); | ||||||
|             AnsiConsole.Write(tree); |         AnsiConsole.Write(tree); | ||||||
|         } |     } | ||||||
|  |  | ||||||
|         private static Tree BuildTree() |     private static Tree BuildTree() | ||||||
|         { |     { | ||||||
|             // Create the tree |         // Create the tree | ||||||
|             var tree = new Tree("Root") |         var tree = new Tree("Root") | ||||||
|                 .Style(Style.Parse("red")) |             .Style(Style.Parse("red")) | ||||||
|                 .Guide(TreeGuide.Line); |             .Guide(TreeGuide.Line); | ||||||
|  |  | ||||||
|             // Add some nodes |         // Add some nodes | ||||||
|             var foo = tree.AddNode("[yellow]Foo[/]"); |         var foo = tree.AddNode("[yellow]Foo[/]"); | ||||||
|             var table = foo.AddNode(new Table() |         var table = foo.AddNode(new Table() | ||||||
|                 .RoundedBorder() |             .RoundedBorder() | ||||||
|                 .AddColumn("First") |             .AddColumn("First") | ||||||
|                 .AddColumn("Second") |             .AddColumn("Second") | ||||||
|                 .AddRow("1", "2") |             .AddRow("1", "2") | ||||||
|                 .AddRow("3", "4") |             .AddRow("3", "4") | ||||||
|                 .AddRow("5", "6")); |             .AddRow("5", "6")); | ||||||
|  |  | ||||||
|             table.AddNode("[blue]Baz[/]"); |         table.AddNode("[blue]Baz[/]"); | ||||||
|             foo.AddNode("Qux"); |         foo.AddNode("Qux"); | ||||||
|  |  | ||||||
|             var bar = tree.AddNode("[yellow]Bar[/]"); |         var bar = tree.AddNode("[yellow]Bar[/]"); | ||||||
|             bar.AddNode(new Calendar(2020, 12) |         bar.AddNode(new Calendar(2020, 12) | ||||||
|                 .AddCalendarEvent(2020, 12, 12) |             .AddCalendarEvent(2020, 12, 12) | ||||||
|                 .HideHeader()); |             .HideHeader()); | ||||||
|  |  | ||||||
|             // Return the tree |         // Return the tree | ||||||
|             return tree; |         return tree; | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -2,123 +2,122 @@ using System; | |||||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||||
| using Spectre.Console.Rendering; | 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; |         _height = height; | ||||||
|         private int? _width; |     } | ||||||
|  |  | ||||||
|         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<Segment> 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) |         return width; | ||||||
|             : this(height) |     } | ||||||
|  |  | ||||||
|  |     private static (float, float, float) ColorFromHSL(double h, double l, double s) | ||||||
|  |     { | ||||||
|  |         double r = 0, g = 0, b = 0; | ||||||
|  |         if (l != 0) | ||||||
|         { |         { | ||||||
|             _width = width; |             if (s == 0) | ||||||
|         } |  | ||||||
|  |  | ||||||
|         protected override Measurement Measure(RenderContext context, int maxWidth) |  | ||||||
|         { |  | ||||||
|             return new Measurement(1, GetWidth(maxWidth)); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         protected override IEnumerable<Segment> Render(RenderContext context, int maxWidth) |  | ||||||
|         { |  | ||||||
|             maxWidth = GetWidth(maxWidth); |  | ||||||
|  |  | ||||||
|             for (var y = 0; y < _height; y++) |  | ||||||
|             { |             { | ||||||
|                 for (var x = 0; x < maxWidth; x++) |                 r = g = b = l; | ||||||
|                 { |  | ||||||
|                     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); |  | ||||||
|             } |             } | ||||||
|             else |             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; | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,15 +1,14 @@ | |||||||
| namespace Spectre.Console.Examples | namespace Spectre.Console.Examples; | ||||||
| { |  | ||||||
|     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) | public static class ColorExtensions | ||||||
|         { | { | ||||||
|             return (float)((0.2126 * color.R) + (0.7152 * color.G) + (0.0722 * color.B)); |     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)); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| <Project> | <Project> | ||||||
|   <PropertyGroup Label="Settings"> |   <PropertyGroup Label="Settings"> | ||||||
|     <Deterministic>true</Deterministic> |     <Deterministic>true</Deterministic> | ||||||
|     <LangVersion>9.0</LangVersion> |     <LangVersion>10</LangVersion> | ||||||
|     <DebugSymbols>true</DebugSymbols> |     <DebugSymbols>true</DebugSymbols> | ||||||
|     <DebugType>embedded</DebugType> |     <DebugType>embedded</DebugType> | ||||||
|     <MinVerSkip Condition="'$(Configuration)' == 'Debug'">true</MinVerSkip> |     <MinVerSkip Condition="'$(Configuration)' == 'Debug'">true</MinVerSkip> | ||||||
|   | |||||||
| @@ -1,16 +1,15 @@ | |||||||
| namespace Spectre.Console.Analyzer.Sandbox | namespace Spectre.Console.Analyzer.Sandbox; | ||||||
|  |  | ||||||
|  | /// <summary> | ||||||
|  | /// Sample sandbox for testing out analyzers. | ||||||
|  | /// </summary> | ||||||
|  | public static class Program | ||||||
| { | { | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// Sample sandbox for testing out analyzers. |     /// The program's entry point. | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     public static class Program |     public static void Main() | ||||||
|     { |     { | ||||||
|         /// <summary> |         AnsiConsole.WriteLine("Project is set up with a reference to Spectre.Console.Analyzer"); | ||||||
|         /// The program's entry point. |  | ||||||
|         /// </summary> |  | ||||||
|         public static void Main() |  | ||||||
|         { |  | ||||||
|             AnsiConsole.WriteLine("Project is set up with a reference to Spectre.Console.Analyzer"); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -6,90 +6,89 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; | |||||||
| using Microsoft.CodeAnalysis.Diagnostics; | using Microsoft.CodeAnalysis.Diagnostics; | ||||||
| using Microsoft.CodeAnalysis.Operations; | using Microsoft.CodeAnalysis.Operations; | ||||||
|  |  | ||||||
| namespace Spectre.Console.Analyzer | namespace Spectre.Console.Analyzer; | ||||||
|  |  | ||||||
|  | /// <summary> | ||||||
|  | /// Analyzer to suggest using available instances of AnsiConsole over the static methods. | ||||||
|  | /// </summary> | ||||||
|  | [DiagnosticAnalyzer(LanguageNames.CSharp)] | ||||||
|  | public class FavorInstanceAnsiConsoleOverStaticAnalyzer : SpectreAnalyzer | ||||||
| { | { | ||||||
|     /// <summary> |     private static readonly DiagnosticDescriptor _diagnosticDescriptor = | ||||||
|     /// Analyzer to suggest using available instances of AnsiConsole over the static methods. |         Descriptors.S1010_FavorInstanceAnsiConsoleOverStatic; | ||||||
|     /// </summary> |  | ||||||
|     [DiagnosticAnalyzer(LanguageNames.CSharp)] |     /// <inheritdoc /> | ||||||
|     public class FavorInstanceAnsiConsoleOverStaticAnalyzer : SpectreAnalyzer |     public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => | ||||||
|  |         ImmutableArray.Create(_diagnosticDescriptor); | ||||||
|  |  | ||||||
|  |     /// <inheritdoc /> | ||||||
|  |     protected override void AnalyzeCompilation(CompilationStartAnalysisContext compilationStartContext) | ||||||
|     { |     { | ||||||
|         private static readonly DiagnosticDescriptor _diagnosticDescriptor = |         compilationStartContext.RegisterOperationAction( | ||||||
|             Descriptors.S1010_FavorInstanceAnsiConsoleOverStatic; |             context => | ||||||
|  |             { | ||||||
|  |                 var ansiConsoleType = context.Compilation.GetTypeByMetadataName("Spectre.Console.AnsiConsole"); | ||||||
|  |  | ||||||
|         /// <inheritdoc /> |                 // if this operation isn't an invocation against one of the System.Console methods | ||||||
|         public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => |                 // defined in _methods then we can safely stop analyzing and return; | ||||||
|             ImmutableArray.Create(_diagnosticDescriptor); |                 var invocationOperation = (IInvocationOperation)context.Operation; | ||||||
|  |                 if (!Equals(invocationOperation.TargetMethod.ContainingType, ansiConsoleType)) | ||||||
|         /// <inheritdoc /> |  | ||||||
|         protected override void AnalyzeCompilation(CompilationStartAnalysisContext compilationStartContext) |  | ||||||
|         { |  | ||||||
|             compilationStartContext.RegisterOperationAction( |  | ||||||
|                 context => |  | ||||||
|                 { |                 { | ||||||
|                     var ansiConsoleType = context.Compilation.GetTypeByMetadataName("Spectre.Console.AnsiConsole"); |                     return; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|                     // if this operation isn't an invocation against one of the System.Console methods |                 // if we aren't in a method then it might be too complex for us to handle. | ||||||
|                     // defined in _methods then we can safely stop analyzing and return; |                 if (!invocationOperation.Syntax.Ancestors().OfType<MethodDeclarationSyntax>().Any()) | ||||||
|                     var invocationOperation = (IInvocationOperation)context.Operation; |                 { | ||||||
|                     if (!Equals(invocationOperation.TargetMethod.ContainingType, ansiConsoleType)) |                     return; | ||||||
|                     { |                 } | ||||||
|                         return; |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                     // if we aren't in a method then it might be too complex for us to handle. |                 if (!HasFieldAnsiConsole(invocationOperation.Syntax) && | ||||||
|                     if (!invocationOperation.Syntax.Ancestors().OfType<MethodDeclarationSyntax>().Any()) |                     !HasParameterAnsiConsole(invocationOperation.Syntax)) | ||||||
|                     { |                 { | ||||||
|                         return; |                     return; | ||||||
|                     } |                 } | ||||||
|  |  | ||||||
|                     if (!HasFieldAnsiConsole(invocationOperation.Syntax) && |                 var methodSymbol = invocationOperation.TargetMethod; | ||||||
|                         !HasParameterAnsiConsole(invocationOperation.Syntax)) |  | ||||||
|                     { |  | ||||||
|                         return; |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                     var methodSymbol = invocationOperation.TargetMethod; |                 var displayString = SymbolDisplay.ToDisplayString( | ||||||
|  |                     methodSymbol, | ||||||
|  |                     SymbolDisplayFormat.CSharpShortErrorMessageFormat | ||||||
|  |                         .WithParameterOptions(SymbolDisplayParameterOptions.None) | ||||||
|  |                         .WithGenericsOptions(SymbolDisplayGenericsOptions.None)); | ||||||
|  |  | ||||||
|                     var displayString = SymbolDisplay.ToDisplayString( |                 context.ReportDiagnostic( | ||||||
|                         methodSymbol, |                     Diagnostic.Create( | ||||||
|                         SymbolDisplayFormat.CSharpShortErrorMessageFormat |                         _diagnosticDescriptor, | ||||||
|                             .WithParameterOptions(SymbolDisplayParameterOptions.None) |                         invocationOperation.Syntax.GetLocation(), | ||||||
|                             .WithGenericsOptions(SymbolDisplayGenericsOptions.None)); |                         displayString)); | ||||||
|  |             }, OperationKind.Invocation); | ||||||
|                     context.ReportDiagnostic( |  | ||||||
|                         Diagnostic.Create( |  | ||||||
|                             _diagnosticDescriptor, |  | ||||||
|                             invocationOperation.Syntax.GetLocation(), |  | ||||||
|                             displayString)); |  | ||||||
|                 }, OperationKind.Invocation); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         private static bool HasParameterAnsiConsole(SyntaxNode syntaxNode) |  | ||||||
|         { |  | ||||||
|             return syntaxNode |  | ||||||
|                 .Ancestors().OfType<MethodDeclarationSyntax>() |  | ||||||
|                 .First() |  | ||||||
|                 .ParameterList.Parameters |  | ||||||
|                 .Any(i => i.Type.NormalizeWhitespace().ToString() == "IAnsiConsole"); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         private static bool HasFieldAnsiConsole(SyntaxNode syntaxNode) |  | ||||||
|         { |  | ||||||
|             var isStatic = syntaxNode |  | ||||||
|                 .Ancestors() |  | ||||||
|                 .OfType<MethodDeclarationSyntax>() |  | ||||||
|                 .First() |  | ||||||
|                 .Modifiers.Any(i => i.Kind() == SyntaxKind.StaticKeyword); |  | ||||||
|  |  | ||||||
|             return syntaxNode |  | ||||||
|                 .Ancestors().OfType<ClassDeclarationSyntax>() |  | ||||||
|                 .First() |  | ||||||
|                 .Members |  | ||||||
|                 .OfType<FieldDeclarationSyntax>() |  | ||||||
|                 .Any(i => |  | ||||||
|                     i.Declaration.Type.NormalizeWhitespace().ToString() == "IAnsiConsole" && |  | ||||||
|                     (!isStatic ^ i.Modifiers.Any(modifier => modifier.Kind() == SyntaxKind.StaticKeyword))); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } |  | ||||||
|  |     private static bool HasParameterAnsiConsole(SyntaxNode syntaxNode) | ||||||
|  |     { | ||||||
|  |         return syntaxNode | ||||||
|  |             .Ancestors().OfType<MethodDeclarationSyntax>() | ||||||
|  |             .First() | ||||||
|  |             .ParameterList.Parameters | ||||||
|  |             .Any(i => i.Type.NormalizeWhitespace().ToString() == "IAnsiConsole"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private static bool HasFieldAnsiConsole(SyntaxNode syntaxNode) | ||||||
|  |     { | ||||||
|  |         var isStatic = syntaxNode | ||||||
|  |             .Ancestors() | ||||||
|  |             .OfType<MethodDeclarationSyntax>() | ||||||
|  |             .First() | ||||||
|  |             .Modifiers.Any(i => i.Kind() == SyntaxKind.StaticKeyword); | ||||||
|  |  | ||||||
|  |         return syntaxNode | ||||||
|  |             .Ancestors().OfType<ClassDeclarationSyntax>() | ||||||
|  |             .First() | ||||||
|  |             .Members | ||||||
|  |             .OfType<FieldDeclarationSyntax>() | ||||||
|  |             .Any(i => | ||||||
|  |                 i.Declaration.Type.NormalizeWhitespace().ToString() == "IAnsiConsole" && | ||||||
|  |                 (!isStatic ^ i.Modifiers.Any(modifier => modifier.Kind() == SyntaxKind.StaticKeyword))); | ||||||
|  |     } | ||||||
|  | } | ||||||
|   | |||||||
| @@ -7,72 +7,71 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; | |||||||
| using Microsoft.CodeAnalysis.Diagnostics; | using Microsoft.CodeAnalysis.Diagnostics; | ||||||
| using Microsoft.CodeAnalysis.Operations; | using Microsoft.CodeAnalysis.Operations; | ||||||
|  |  | ||||||
| namespace Spectre.Console.Analyzer | namespace Spectre.Console.Analyzer; | ||||||
|  |  | ||||||
|  | /// <summary> | ||||||
|  | /// Analyzer to detect calls to live renderables within a live renderable context. | ||||||
|  | /// </summary> | ||||||
|  | [DiagnosticAnalyzer(LanguageNames.CSharp)] | ||||||
|  | [Shared] | ||||||
|  | public class NoConcurrentLiveRenderablesAnalyzer : SpectreAnalyzer | ||||||
| { | { | ||||||
|     /// <summary> |     private static readonly DiagnosticDescriptor _diagnosticDescriptor = | ||||||
|     /// Analyzer to detect calls to live renderables within a live renderable context. |         Descriptors.S1020_AvoidConcurrentCallsToMultipleLiveRenderables; | ||||||
|     /// </summary> |  | ||||||
|     [DiagnosticAnalyzer(LanguageNames.CSharp)] |     /// <inheritdoc /> | ||||||
|     [Shared] |     public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => | ||||||
|     public class NoConcurrentLiveRenderablesAnalyzer : SpectreAnalyzer |         ImmutableArray.Create(_diagnosticDescriptor); | ||||||
|  |  | ||||||
|  |     /// <inheritdoc /> | ||||||
|  |     protected override void AnalyzeCompilation(CompilationStartAnalysisContext compilationStartContext) | ||||||
|     { |     { | ||||||
|         private static readonly DiagnosticDescriptor _diagnosticDescriptor = |         compilationStartContext.RegisterOperationAction( | ||||||
|             Descriptors.S1020_AvoidConcurrentCallsToMultipleLiveRenderables; |             context => | ||||||
|  |             { | ||||||
|  |                 var invocationOperation = (IInvocationOperation)context.Operation; | ||||||
|  |                 var methodSymbol = invocationOperation.TargetMethod; | ||||||
|  |  | ||||||
|         /// <inheritdoc /> |                 const string StartMethod = "Start"; | ||||||
|         public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => |                 if (methodSymbol.Name != StartMethod) | ||||||
|             ImmutableArray.Create(_diagnosticDescriptor); |  | ||||||
|  |  | ||||||
|         /// <inheritdoc /> |  | ||||||
|         protected override void AnalyzeCompilation(CompilationStartAnalysisContext compilationStartContext) |  | ||||||
|         { |  | ||||||
|             compilationStartContext.RegisterOperationAction( |  | ||||||
|                 context => |  | ||||||
|                 { |                 { | ||||||
|                     var invocationOperation = (IInvocationOperation)context.Operation; |                     return; | ||||||
|                     var methodSymbol = invocationOperation.TargetMethod; |                 } | ||||||
|  |  | ||||||
|                     const string StartMethod = "Start"; |                 var liveTypes = Constants.LiveRenderables | ||||||
|                     if (methodSymbol.Name != StartMethod) |                     .Select(i => context.Compilation.GetTypeByMetadataName(i)) | ||||||
|                     { |                     .ToImmutableArray(); | ||||||
|                         return; |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                     var liveTypes = Constants.LiveRenderables |                 if (liveTypes.All(i => !Equals(i, methodSymbol.ContainingType))) | ||||||
|                         .Select(i => context.Compilation.GetTypeByMetadataName(i)) |                 { | ||||||
|                         .ToImmutableArray(); |                     return; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|                     if (liveTypes.All(i => !Equals(i, methodSymbol.ContainingType))) |                 var model = context.Compilation.GetSemanticModel(context.Operation.Syntax.SyntaxTree); | ||||||
|                     { |                 var parentInvocations = invocationOperation | ||||||
|                         return; |                     .Syntax.Ancestors() | ||||||
|                     } |                     .OfType<InvocationExpressionSyntax>() | ||||||
|  |                     .Select(i => model.GetOperation(i)) | ||||||
|  |                     .OfType<IInvocationOperation>() | ||||||
|  |                     .ToList(); | ||||||
|  |  | ||||||
|                     var model = context.Compilation.GetSemanticModel(context.Operation.Syntax.SyntaxTree); |                 if (parentInvocations.All(parent => | ||||||
|                     var parentInvocations = invocationOperation |                     parent.TargetMethod.Name != StartMethod || !liveTypes.Contains(parent.TargetMethod.ContainingType))) | ||||||
|                         .Syntax.Ancestors() |                 { | ||||||
|                         .OfType<InvocationExpressionSyntax>() |                     return; | ||||||
|                         .Select(i => model.GetOperation(i)) |                 } | ||||||
|                         .OfType<IInvocationOperation>() |  | ||||||
|                         .ToList(); |  | ||||||
|  |  | ||||||
|                     if (parentInvocations.All(parent => |                 var displayString = SymbolDisplay.ToDisplayString( | ||||||
|                         parent.TargetMethod.Name != StartMethod || !liveTypes.Contains(parent.TargetMethod.ContainingType))) |                     methodSymbol, | ||||||
|                     { |                     SymbolDisplayFormat.CSharpShortErrorMessageFormat | ||||||
|                         return; |                         .WithParameterOptions(SymbolDisplayParameterOptions.None) | ||||||
|                     } |                         .WithGenericsOptions(SymbolDisplayGenericsOptions.None)); | ||||||
|  |  | ||||||
|                     var displayString = SymbolDisplay.ToDisplayString( |                 context.ReportDiagnostic( | ||||||
|                         methodSymbol, |                     Diagnostic.Create( | ||||||
|                         SymbolDisplayFormat.CSharpShortErrorMessageFormat |                         _diagnosticDescriptor, | ||||||
|                             .WithParameterOptions(SymbolDisplayParameterOptions.None) |                         invocationOperation.Syntax.GetLocation(), | ||||||
|                             .WithGenericsOptions(SymbolDisplayGenericsOptions.None)); |                         displayString)); | ||||||
|  |             }, OperationKind.Invocation); | ||||||
|                     context.ReportDiagnostic( |  | ||||||
|                         Diagnostic.Create( |  | ||||||
|                             _diagnosticDescriptor, |  | ||||||
|                             invocationOperation.Syntax.GetLocation(), |  | ||||||
|                             displayString)); |  | ||||||
|                 }, OperationKind.Invocation); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -7,78 +7,77 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; | |||||||
| using Microsoft.CodeAnalysis.Diagnostics; | using Microsoft.CodeAnalysis.Diagnostics; | ||||||
| using Microsoft.CodeAnalysis.Operations; | using Microsoft.CodeAnalysis.Operations; | ||||||
|  |  | ||||||
| namespace Spectre.Console.Analyzer | namespace Spectre.Console.Analyzer; | ||||||
|  |  | ||||||
|  | /// <summary> | ||||||
|  | /// Analyzer to detect calls to live renderables within a live renderable context. | ||||||
|  | /// </summary> | ||||||
|  | [DiagnosticAnalyzer(LanguageNames.CSharp)] | ||||||
|  | [Shared] | ||||||
|  | public class NoPromptsDuringLiveRenderablesAnalyzer : SpectreAnalyzer | ||||||
| { | { | ||||||
|     /// <summary> |     private static readonly DiagnosticDescriptor _diagnosticDescriptor = | ||||||
|     /// Analyzer to detect calls to live renderables within a live renderable context. |         Descriptors.S1021_AvoidPromptCallsDuringLiveRenderables; | ||||||
|     /// </summary> |  | ||||||
|     [DiagnosticAnalyzer(LanguageNames.CSharp)] |     /// <inheritdoc /> | ||||||
|     [Shared] |     public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => | ||||||
|     public class NoPromptsDuringLiveRenderablesAnalyzer : SpectreAnalyzer |         ImmutableArray.Create(_diagnosticDescriptor); | ||||||
|  |  | ||||||
|  |     /// <inheritdoc /> | ||||||
|  |     protected override void AnalyzeCompilation(CompilationStartAnalysisContext compilationStartContext) | ||||||
|     { |     { | ||||||
|         private static readonly DiagnosticDescriptor _diagnosticDescriptor = |         compilationStartContext.RegisterOperationAction( | ||||||
|             Descriptors.S1021_AvoidPromptCallsDuringLiveRenderables; |             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; | ||||||
|  |  | ||||||
|         /// <inheritdoc /> |                 var promptMethods = ImmutableArray.Create("Ask", "Confirm", "Prompt"); | ||||||
|         public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => |                 if (!promptMethods.Contains(methodSymbol.Name)) | ||||||
|             ImmutableArray.Create(_diagnosticDescriptor); |  | ||||||
|  |  | ||||||
|         /// <inheritdoc /> |  | ||||||
|         protected override void AnalyzeCompilation(CompilationStartAnalysisContext compilationStartContext) |  | ||||||
|         { |  | ||||||
|             compilationStartContext.RegisterOperationAction( |  | ||||||
|                 context => |  | ||||||
|                 { |                 { | ||||||
|                     // if this operation isn't an invocation against one of the System.Console methods |                     return; | ||||||
|                     // defined in _methods then we can safely stop analyzing and return; |                 } | ||||||
|                     var invocationOperation = (IInvocationOperation)context.Operation; |  | ||||||
|                     var methodSymbol = invocationOperation.TargetMethod; |  | ||||||
|  |  | ||||||
|                     var promptMethods = ImmutableArray.Create("Ask", "Confirm", "Prompt"); |                 var ansiConsoleType = context.Compilation.GetTypeByMetadataName("Spectre.Console.AnsiConsole"); | ||||||
|                     if (!promptMethods.Contains(methodSymbol.Name)) |                 var ansiConsoleExtensionsType = context.Compilation.GetTypeByMetadataName("Spectre.Console.AnsiConsoleExtensions"); | ||||||
|                     { |  | ||||||
|                         return; |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                     var ansiConsoleType = context.Compilation.GetTypeByMetadataName("Spectre.Console.AnsiConsole"); |                 if (!Equals(methodSymbol.ContainingType, ansiConsoleType) && !Equals(methodSymbol.ContainingType, ansiConsoleExtensionsType)) | ||||||
|                     var ansiConsoleExtensionsType = context.Compilation.GetTypeByMetadataName("Spectre.Console.AnsiConsoleExtensions"); |                 { | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|                     if (!Equals(methodSymbol.ContainingType, ansiConsoleType) && !Equals(methodSymbol.ContainingType, ansiConsoleExtensionsType)) |                 var model = context.Compilation.GetSemanticModel(context.Operation.Syntax.SyntaxTree); | ||||||
|                     { |                 var parentInvocations = invocationOperation | ||||||
|                         return; |                     .Syntax.Ancestors() | ||||||
|                     } |                     .OfType<InvocationExpressionSyntax>() | ||||||
|  |                     .Select(i => model.GetOperation(i)) | ||||||
|  |                     .OfType<IInvocationOperation>() | ||||||
|  |                     .ToList(); | ||||||
|  |  | ||||||
|                     var model = context.Compilation.GetSemanticModel(context.Operation.Syntax.SyntaxTree); |                 var liveTypes = Constants.LiveRenderables | ||||||
|                     var parentInvocations = invocationOperation |                     .Select(i => context.Compilation.GetTypeByMetadataName(i)) | ||||||
|                         .Syntax.Ancestors() |                     .ToImmutableArray(); | ||||||
|                         .OfType<InvocationExpressionSyntax>() |  | ||||||
|                         .Select(i => model.GetOperation(i)) |  | ||||||
|                         .OfType<IInvocationOperation>() |  | ||||||
|                         .ToList(); |  | ||||||
|  |  | ||||||
|                     var liveTypes = Constants.LiveRenderables |                 if (parentInvocations.All(parent => | ||||||
|                         .Select(i => context.Compilation.GetTypeByMetadataName(i)) |                     parent.TargetMethod.Name != "Start" || | ||||||
|                         .ToImmutableArray(); |                     !liveTypes.Contains(parent.TargetMethod.ContainingType))) | ||||||
|  |                 { | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|                     if (parentInvocations.All(parent => |                 var displayString = SymbolDisplay.ToDisplayString( | ||||||
|                         parent.TargetMethod.Name != "Start" || |                     methodSymbol, | ||||||
|                         !liveTypes.Contains(parent.TargetMethod.ContainingType))) |                     SymbolDisplayFormat.CSharpShortErrorMessageFormat | ||||||
|                     { |                         .WithParameterOptions(SymbolDisplayParameterOptions.None) | ||||||
|                         return; |                         .WithGenericsOptions(SymbolDisplayGenericsOptions.None)); | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                     var displayString = SymbolDisplay.ToDisplayString( |                 context.ReportDiagnostic( | ||||||
|                         methodSymbol, |                     Diagnostic.Create( | ||||||
|                         SymbolDisplayFormat.CSharpShortErrorMessageFormat |                         _diagnosticDescriptor, | ||||||
|                             .WithParameterOptions(SymbolDisplayParameterOptions.None) |                         invocationOperation.Syntax.GetLocation(), | ||||||
|                             .WithGenericsOptions(SymbolDisplayGenericsOptions.None)); |                         displayString)); | ||||||
|  |             }, OperationKind.Invocation); | ||||||
|                     context.ReportDiagnostic( |  | ||||||
|                         Diagnostic.Create( |  | ||||||
|                             _diagnosticDescriptor, |  | ||||||
|                             invocationOperation.Syntax.GetLocation(), |  | ||||||
|                             displayString)); |  | ||||||
|                 }, OperationKind.Invocation); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,25 +1,24 @@ | |||||||
| using Microsoft.CodeAnalysis.Diagnostics; | using Microsoft.CodeAnalysis.Diagnostics; | ||||||
|  |  | ||||||
| namespace Spectre.Console.Analyzer | namespace Spectre.Console.Analyzer; | ||||||
|  |  | ||||||
|  | /// <summary> | ||||||
|  | /// Base class for Spectre analyzers. | ||||||
|  | /// </summary> | ||||||
|  | public abstract class SpectreAnalyzer : DiagnosticAnalyzer | ||||||
| { | { | ||||||
|     /// <summary> |     /// <inheritdoc /> | ||||||
|     /// Base class for Spectre analyzers. |     public override void Initialize(AnalysisContext context) | ||||||
|     /// </summary> |  | ||||||
|     public abstract class SpectreAnalyzer : DiagnosticAnalyzer |  | ||||||
|     { |     { | ||||||
|         /// <inheritdoc /> |         context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); | ||||||
|         public override void Initialize(AnalysisContext context) |         context.EnableConcurrentExecution(); | ||||||
|         { |  | ||||||
|             context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); |  | ||||||
|             context.EnableConcurrentExecution(); |  | ||||||
|  |  | ||||||
|             context.RegisterCompilationStartAction(AnalyzeCompilation); |         context.RegisterCompilationStartAction(AnalyzeCompilation); | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Analyze compilation. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="compilationStartContext">Compilation Start Analysis Context.</param> |  | ||||||
|         protected abstract void AnalyzeCompilation(CompilationStartAnalysisContext compilationStartContext); |  | ||||||
|     } |     } | ||||||
| } |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Analyze compilation. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="compilationStartContext">Compilation Start Analysis Context.</param> | ||||||
|  |     protected abstract void AnalyzeCompilation(CompilationStartAnalysisContext compilationStartContext); | ||||||
|  | } | ||||||
|   | |||||||
| @@ -4,60 +4,59 @@ using Microsoft.CodeAnalysis.CSharp; | |||||||
| using Microsoft.CodeAnalysis.Diagnostics; | using Microsoft.CodeAnalysis.Diagnostics; | ||||||
| using Microsoft.CodeAnalysis.Operations; | using Microsoft.CodeAnalysis.Operations; | ||||||
|  |  | ||||||
| namespace Spectre.Console.Analyzer | namespace Spectre.Console.Analyzer; | ||||||
|  |  | ||||||
|  | /// <summary> | ||||||
|  | /// Analyzer to enforce the use of AnsiConsole over System.Console for known methods. | ||||||
|  | /// </summary> | ||||||
|  | [DiagnosticAnalyzer(LanguageNames.CSharp)] | ||||||
|  | public class UseSpectreInsteadOfSystemConsoleAnalyzer : SpectreAnalyzer | ||||||
| { | { | ||||||
|     /// <summary> |     private static readonly DiagnosticDescriptor _diagnosticDescriptor = | ||||||
|     /// Analyzer to enforce the use of AnsiConsole over System.Console for known methods. |         Descriptors.S1000_UseAnsiConsoleOverSystemConsole; | ||||||
|     /// </summary> |  | ||||||
|     [DiagnosticAnalyzer(LanguageNames.CSharp)] |     private static readonly string[] _methods = { "WriteLine", "Write" }; | ||||||
|     public class UseSpectreInsteadOfSystemConsoleAnalyzer : SpectreAnalyzer |  | ||||||
|  |     /// <inheritdoc /> | ||||||
|  |     public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => | ||||||
|  |         ImmutableArray.Create(_diagnosticDescriptor); | ||||||
|  |  | ||||||
|  |     /// <inheritdoc /> | ||||||
|  |     protected override void AnalyzeCompilation(CompilationStartAnalysisContext compilationStartContext) | ||||||
|     { |     { | ||||||
|         private static readonly DiagnosticDescriptor _diagnosticDescriptor = |         compilationStartContext.RegisterOperationAction( | ||||||
|             Descriptors.S1000_UseAnsiConsoleOverSystemConsole; |             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" }; |                 var methodName = System.Array.Find(_methods, i => i.Equals(invocationOperation.TargetMethod.Name)); | ||||||
|  |                 if (methodName == null) | ||||||
|         /// <inheritdoc /> |  | ||||||
|         public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => |  | ||||||
|             ImmutableArray.Create(_diagnosticDescriptor); |  | ||||||
|  |  | ||||||
|         /// <inheritdoc /> |  | ||||||
|         protected override void AnalyzeCompilation(CompilationStartAnalysisContext compilationStartContext) |  | ||||||
|         { |  | ||||||
|             compilationStartContext.RegisterOperationAction( |  | ||||||
|                 context => |  | ||||||
|                 { |                 { | ||||||
|                     // if this operation isn't an invocation against one of the System.Console methods |                     return; | ||||||
|                     // defined in _methods then we can safely stop analyzing and return; |                 } | ||||||
|                     var invocationOperation = (IInvocationOperation)context.Operation; |  | ||||||
|  |  | ||||||
|                     var methodName = System.Array.Find(_methods, i => i.Equals(invocationOperation.TargetMethod.Name)); |                 var systemConsoleType = context.Compilation.GetTypeByMetadataName("System.Console"); | ||||||
|                     if (methodName == null) |  | ||||||
|                     { |  | ||||||
|                         return; |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                     var systemConsoleType = context.Compilation.GetTypeByMetadataName("System.Console"); |                 if (!Equals(invocationOperation.TargetMethod.ContainingType, systemConsoleType)) | ||||||
|  |                 { | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|                     if (!Equals(invocationOperation.TargetMethod.ContainingType, systemConsoleType)) |                 var methodSymbol = invocationOperation.TargetMethod; | ||||||
|                     { |  | ||||||
|                         return; |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                     var methodSymbol = invocationOperation.TargetMethod; |                 var displayString = SymbolDisplay.ToDisplayString( | ||||||
|  |                     methodSymbol, | ||||||
|  |                     SymbolDisplayFormat.CSharpShortErrorMessageFormat | ||||||
|  |                         .WithParameterOptions(SymbolDisplayParameterOptions.None) | ||||||
|  |                         .WithGenericsOptions(SymbolDisplayGenericsOptions.None)); | ||||||
|  |  | ||||||
|                     var displayString = SymbolDisplay.ToDisplayString( |                 context.ReportDiagnostic( | ||||||
|                         methodSymbol, |                     Diagnostic.Create( | ||||||
|                         SymbolDisplayFormat.CSharpShortErrorMessageFormat |                         _diagnosticDescriptor, | ||||||
|                             .WithParameterOptions(SymbolDisplayParameterOptions.None) |                         invocationOperation.Syntax.GetLocation(), | ||||||
|                             .WithGenericsOptions(SymbolDisplayGenericsOptions.None)); |                         displayString)); | ||||||
|  |             }, OperationKind.Invocation); | ||||||
|                     context.ReportDiagnostic( |  | ||||||
|                         Diagnostic.Create( |  | ||||||
|                             _diagnosticDescriptor, |  | ||||||
|                             invocationOperation.Syntax.GetLocation(), |  | ||||||
|                             displayString)); |  | ||||||
|                 }, OperationKind.Invocation); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,15 +1,14 @@ | |||||||
| namespace Spectre.Console.Analyzer | namespace Spectre.Console.Analyzer; | ||||||
| { |  | ||||||
|     internal static class Constants |  | ||||||
|     { |  | ||||||
|         internal const string StaticInstance = "AnsiConsole"; |  | ||||||
|         internal const string SpectreConsole = "Spectre.Console"; |  | ||||||
|  |  | ||||||
|         internal static readonly string[] LiveRenderables = | internal static class Constants | ||||||
|         { | { | ||||||
|             "Spectre.Console.LiveDisplay", |     internal const string StaticInstance = "AnsiConsole"; | ||||||
|             "Spectre.Console.Progress", |     internal const string SpectreConsole = "Spectre.Console"; | ||||||
|             "Spectre.Console.Status", |  | ||||||
|         }; |     internal static readonly string[] LiveRenderables = | ||||||
|     } |     { | ||||||
| } |         "Spectre.Console.LiveDisplay", | ||||||
|  |         "Spectre.Console.Progress", | ||||||
|  |         "Spectre.Console.Status", | ||||||
|  |     }; | ||||||
|  | } | ||||||
|   | |||||||
| @@ -3,77 +3,76 @@ using Microsoft.CodeAnalysis; | |||||||
| using static Microsoft.CodeAnalysis.DiagnosticSeverity; | using static Microsoft.CodeAnalysis.DiagnosticSeverity; | ||||||
| using static Spectre.Console.Analyzer.Descriptors.Category; | using static Spectre.Console.Analyzer.Descriptors.Category; | ||||||
|  |  | ||||||
| namespace Spectre.Console.Analyzer | namespace Spectre.Console.Analyzer; | ||||||
|  |  | ||||||
|  | /// <summary> | ||||||
|  | /// Code analysis descriptors. | ||||||
|  | /// </summary> | ||||||
|  | public static class Descriptors | ||||||
| { | { | ||||||
|     /// <summary> |     internal enum Category | ||||||
|     /// Code analysis descriptors. |  | ||||||
|     /// </summary> |  | ||||||
|     public static class Descriptors |  | ||||||
|     { |     { | ||||||
|         internal enum Category |         Usage, // 1xxx | ||||||
|         { |  | ||||||
|             Usage, // 1xxx |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         private static readonly ConcurrentDictionary<Category, string> _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); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Gets definitions of diagnostics Spectre1000. |  | ||||||
|         /// </summary> |  | ||||||
|         public static DiagnosticDescriptor S1000_UseAnsiConsoleOverSystemConsole { get; } = |  | ||||||
|             Rule( |  | ||||||
|                 "Spectre1000", |  | ||||||
|                 "Use AnsiConsole instead of System.Console", |  | ||||||
|                 Usage, |  | ||||||
|                 Warning, |  | ||||||
|                 "Use AnsiConsole instead of System.Console"); |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Gets definitions of diagnostics Spectre1010. |  | ||||||
|         /// </summary> |  | ||||||
|         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."); |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Gets definitions of diagnostics Spectre1020. |  | ||||||
|         /// </summary> |  | ||||||
|         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."); |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Gets definitions of diagnostics Spectre1020. |  | ||||||
|         /// </summary> |  | ||||||
|         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."); |  | ||||||
|     } |     } | ||||||
| } |  | ||||||
|  |     private static readonly ConcurrentDictionary<Category, string> _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); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Gets definitions of diagnostics Spectre1000. | ||||||
|  |     /// </summary> | ||||||
|  |     public static DiagnosticDescriptor S1000_UseAnsiConsoleOverSystemConsole { get; } = | ||||||
|  |         Rule( | ||||||
|  |             "Spectre1000", | ||||||
|  |             "Use AnsiConsole instead of System.Console", | ||||||
|  |             Usage, | ||||||
|  |             Warning, | ||||||
|  |             "Use AnsiConsole instead of System.Console"); | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Gets definitions of diagnostics Spectre1010. | ||||||
|  |     /// </summary> | ||||||
|  |     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."); | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Gets definitions of diagnostics Spectre1020. | ||||||
|  |     /// </summary> | ||||||
|  |     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."); | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Gets definitions of diagnostics Spectre1020. | ||||||
|  |     /// </summary> | ||||||
|  |     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."); | ||||||
|  | } | ||||||
|   | |||||||
| @@ -7,110 +7,109 @@ using Microsoft.CodeAnalysis.CSharp; | |||||||
| using Microsoft.CodeAnalysis.CSharp.Syntax; | using Microsoft.CodeAnalysis.CSharp.Syntax; | ||||||
| using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; | using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; | ||||||
|  |  | ||||||
| namespace Spectre.Console.Analyzer.CodeActions | namespace Spectre.Console.Analyzer.CodeActions; | ||||||
|  |  | ||||||
|  | /// <summary> | ||||||
|  | /// Code action to change calls to System.Console to AnsiConsole. | ||||||
|  | /// </summary> | ||||||
|  | public class SwitchToAnsiConsoleAction : CodeAction | ||||||
| { | { | ||||||
|  |     private readonly Document _document; | ||||||
|  |     private readonly InvocationExpressionSyntax _originalInvocation; | ||||||
|  |  | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// Code action to change calls to System.Console to AnsiConsole. |     /// Initializes a new instance of the <see cref="SwitchToAnsiConsoleAction"/> class. | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     public class SwitchToAnsiConsoleAction : CodeAction |     /// <param name="document">Document to change.</param> | ||||||
|  |     /// <param name="originalInvocation">The method to change.</param> | ||||||
|  |     /// <param name="title">Title of the fix.</param> | ||||||
|  |     public SwitchToAnsiConsoleAction(Document document, InvocationExpressionSyntax originalInvocation, string title) | ||||||
|     { |     { | ||||||
|         private readonly Document _document; |         _document = document; | ||||||
|         private readonly InvocationExpressionSyntax _originalInvocation; |         _originalInvocation = originalInvocation; | ||||||
|  |         Title = title; | ||||||
|         /// <summary> |  | ||||||
|         /// Initializes a new instance of the <see cref="SwitchToAnsiConsoleAction"/> class. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="document">Document to change.</param> |  | ||||||
|         /// <param name="originalInvocation">The method to change.</param> |  | ||||||
|         /// <param name="title">Title of the fix.</param> |  | ||||||
|         public SwitchToAnsiConsoleAction(Document document, InvocationExpressionSyntax originalInvocation, string title) |  | ||||||
|         { |  | ||||||
|             _document = document; |  | ||||||
|             _originalInvocation = originalInvocation; |  | ||||||
|             Title = title; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <inheritdoc /> |  | ||||||
|         public override string Title { get; } |  | ||||||
|  |  | ||||||
|         /// <inheritdoc /> |  | ||||||
|         public override string EquivalenceKey => Title; |  | ||||||
|  |  | ||||||
|         /// <inheritdoc /> |  | ||||||
|         protected override async Task<Document> 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<MethodDeclarationSyntax>() |  | ||||||
|                 .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<MethodDeclarationSyntax>() |  | ||||||
|                 .First() |  | ||||||
|                 .Modifiers.Any(i => i.Kind() == SyntaxKind.StaticKeyword); |  | ||||||
|  |  | ||||||
|             return _originalInvocation |  | ||||||
|                 .Ancestors().OfType<ClassDeclarationSyntax>() |  | ||||||
|                 .First() |  | ||||||
|                 .Members |  | ||||||
|                 .OfType<FieldDeclarationSyntax>() |  | ||||||
|                 .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; |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } |  | ||||||
|  |     /// <inheritdoc /> | ||||||
|  |     public override string Title { get; } | ||||||
|  |  | ||||||
|  |     /// <inheritdoc /> | ||||||
|  |     public override string EquivalenceKey => Title; | ||||||
|  |  | ||||||
|  |     /// <inheritdoc /> | ||||||
|  |     protected override async Task<Document> 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<MethodDeclarationSyntax>() | ||||||
|  |             .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<MethodDeclarationSyntax>() | ||||||
|  |             .First() | ||||||
|  |             .Modifiers.Any(i => i.Kind() == SyntaxKind.StaticKeyword); | ||||||
|  |  | ||||||
|  |         return _originalInvocation | ||||||
|  |             .Ancestors().OfType<ClassDeclarationSyntax>() | ||||||
|  |             .First() | ||||||
|  |             .Members | ||||||
|  |             .OfType<FieldDeclarationSyntax>() | ||||||
|  |             .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; | ||||||
|  |     } | ||||||
|  | } | ||||||
|   | |||||||
| @@ -6,30 +6,29 @@ using Microsoft.CodeAnalysis.CodeFixes; | |||||||
| using Microsoft.CodeAnalysis.CSharp.Syntax; | using Microsoft.CodeAnalysis.CSharp.Syntax; | ||||||
| using Spectre.Console.Analyzer.CodeActions; | using Spectre.Console.Analyzer.CodeActions; | ||||||
|  |  | ||||||
| namespace Spectre.Console.Analyzer.FixProviders | namespace Spectre.Console.Analyzer.FixProviders; | ||||||
|  |  | ||||||
|  | /// <summary> | ||||||
|  | /// Fix provider to change System.Console calls to AnsiConsole calls. | ||||||
|  | /// </summary> | ||||||
|  | [ExportCodeFixProvider(LanguageNames.CSharp)] | ||||||
|  | [Shared] | ||||||
|  | public class StaticAnsiConsoleToInstanceFix : CodeFixProvider | ||||||
| { | { | ||||||
|     /// <summary> |     /// <inheritdoc /> | ||||||
|     /// Fix provider to change System.Console calls to AnsiConsole calls. |     public sealed override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create( | ||||||
|     /// </summary> |         Descriptors.S1010_FavorInstanceAnsiConsoleOverStatic.Id); | ||||||
|     [ExportCodeFixProvider(LanguageNames.CSharp)] |  | ||||||
|     [Shared] |     /// <inheritdoc /> | ||||||
|     public class StaticAnsiConsoleToInstanceFix : CodeFixProvider |     public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; | ||||||
|  |  | ||||||
|  |     /// <inheritdoc /> | ||||||
|  |     public override async Task RegisterCodeFixesAsync(CodeFixContext context) | ||||||
|     { |     { | ||||||
|         /// <inheritdoc /> |         var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); | ||||||
|         public sealed override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create( |         var methodDeclaration = root.FindNode(context.Span).FirstAncestorOrSelf<InvocationExpressionSyntax>(); | ||||||
|             Descriptors.S1010_FavorInstanceAnsiConsoleOverStatic.Id); |         context.RegisterCodeFix( | ||||||
|  |             new SwitchToAnsiConsoleAction(context.Document, methodDeclaration, "Convert static AnsiConsole calls to local instance."), | ||||||
|         /// <inheritdoc /> |             context.Diagnostics); | ||||||
|         public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; |  | ||||||
|  |  | ||||||
|         /// <inheritdoc /> |  | ||||||
|         public override async Task RegisterCodeFixesAsync(CodeFixContext context) |  | ||||||
|         { |  | ||||||
|             var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); |  | ||||||
|             var methodDeclaration = root.FindNode(context.Span).FirstAncestorOrSelf<InvocationExpressionSyntax>(); |  | ||||||
|             context.RegisterCodeFix( |  | ||||||
|                 new SwitchToAnsiConsoleAction(context.Document, methodDeclaration, "Convert static AnsiConsole calls to local instance."), |  | ||||||
|                 context.Diagnostics); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -6,30 +6,29 @@ using Microsoft.CodeAnalysis.CodeFixes; | |||||||
| using Microsoft.CodeAnalysis.CSharp.Syntax; | using Microsoft.CodeAnalysis.CSharp.Syntax; | ||||||
| using Spectre.Console.Analyzer.CodeActions; | using Spectre.Console.Analyzer.CodeActions; | ||||||
|  |  | ||||||
| namespace Spectre.Console.Analyzer.FixProviders | namespace Spectre.Console.Analyzer.FixProviders; | ||||||
|  |  | ||||||
|  | /// <summary> | ||||||
|  | /// Fix provider to change System.Console calls to AnsiConsole calls. | ||||||
|  | /// </summary> | ||||||
|  | [ExportCodeFixProvider(LanguageNames.CSharp)] | ||||||
|  | [Shared] | ||||||
|  | public class SystemConsoleToAnsiConsoleFix : CodeFixProvider | ||||||
| { | { | ||||||
|     /// <summary> |     /// <inheritdoc /> | ||||||
|     /// Fix provider to change System.Console calls to AnsiConsole calls. |     public sealed override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create( | ||||||
|     /// </summary> |         Descriptors.S1000_UseAnsiConsoleOverSystemConsole.Id); | ||||||
|     [ExportCodeFixProvider(LanguageNames.CSharp)] |  | ||||||
|     [Shared] |     /// <inheritdoc /> | ||||||
|     public class SystemConsoleToAnsiConsoleFix : CodeFixProvider |     public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; | ||||||
|  |  | ||||||
|  |     /// <inheritdoc /> | ||||||
|  |     public override async Task RegisterCodeFixesAsync(CodeFixContext context) | ||||||
|     { |     { | ||||||
|         /// <inheritdoc /> |         var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); | ||||||
|         public sealed override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create( |         var methodDeclaration = root.FindNode(context.Span).FirstAncestorOrSelf<InvocationExpressionSyntax>(); | ||||||
|             Descriptors.S1000_UseAnsiConsoleOverSystemConsole.Id); |         context.RegisterCodeFix( | ||||||
|  |             new SwitchToAnsiConsoleAction(context.Document, methodDeclaration, "Convert static call to AnsiConsole to Spectre.Console.AnsiConsole"), | ||||||
|         /// <inheritdoc /> |             context.Diagnostics); | ||||||
|         public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; |  | ||||||
|  |  | ||||||
|         /// <inheritdoc /> |  | ||||||
|         public override async Task RegisterCodeFixesAsync(CodeFixContext context) |  | ||||||
|         { |  | ||||||
|             var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); |  | ||||||
|             var methodDeclaration = root.FindNode(context.Span).FirstAncestorOrSelf<InvocationExpressionSyntax>(); |  | ||||||
|             context.RegisterCodeFix( |  | ||||||
|                 new SwitchToAnsiConsoleAction(context.Document, methodDeclaration, "Convert static call to AnsiConsole to Spectre.Console.AnsiConsole"), |  | ||||||
|                 context.Diagnostics); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,10 +1,9 @@ | |||||||
| using Microsoft.CodeAnalysis.CSharp.Syntax; | using Microsoft.CodeAnalysis.CSharp.Syntax; | ||||||
| using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; | 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"))); | ||||||
|     { | } | ||||||
|         public static readonly UsingDirectiveSyntax SpectreUsing = UsingDirective(QualifiedName(IdentifierName("Spectre"), IdentifierName("Console"))); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -6,139 +6,138 @@ using SixLabors.ImageSharp.Processing; | |||||||
| using SixLabors.ImageSharp.Processing.Processors.Transforms; | using SixLabors.ImageSharp.Processing.Processors.Transforms; | ||||||
| using Spectre.Console.Rendering; | using Spectre.Console.Rendering; | ||||||
|  |  | ||||||
| namespace Spectre.Console | namespace Spectre.Console; | ||||||
|  |  | ||||||
|  | /// <summary> | ||||||
|  | /// Represents a renderable image. | ||||||
|  | /// </summary> | ||||||
|  | public sealed class CanvasImage : Renderable | ||||||
| { | { | ||||||
|  |     private static readonly IResampler _defaultResampler = KnownResamplers.Bicubic; | ||||||
|  |  | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// Represents a renderable image. |     /// Gets the image width. | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     public sealed class CanvasImage : Renderable |     public int Width => Image.Width; | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Gets the image height. | ||||||
|  |     /// </summary> | ||||||
|  |     public int Height => Image.Height; | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Gets or sets the render width of the canvas. | ||||||
|  |     /// </summary> | ||||||
|  |     public int? MaxWidth { get; set; } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Gets or sets the render width of the canvas. | ||||||
|  |     /// </summary> | ||||||
|  |     public int PixelWidth { get; set; } = 2; | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Gets or sets the <see cref="IResampler"/> that should | ||||||
|  |     /// be used when scaling the image. Defaults to bicubic sampling. | ||||||
|  |     /// </summary> | ||||||
|  |     public IResampler? Resampler { get; set; } | ||||||
|  |  | ||||||
|  |     internal SixLabors.ImageSharp.Image<Rgba32> Image { get; } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Initializes a new instance of the <see cref="CanvasImage"/> class. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="filename">The image filename.</param> | ||||||
|  |     public CanvasImage(string filename) | ||||||
|     { |     { | ||||||
|         private static readonly IResampler _defaultResampler = KnownResamplers.Bicubic; |         Image = SixLabors.ImageSharp.Image.Load<Rgba32>(filename); | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Gets the image width. |  | ||||||
|         /// </summary> |  | ||||||
|         public int Width => Image.Width; |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Gets the image height. |  | ||||||
|         /// </summary> |  | ||||||
|         public int Height => Image.Height; |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Gets or sets the render width of the canvas. |  | ||||||
|         /// </summary> |  | ||||||
|         public int? MaxWidth { get; set; } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Gets or sets the render width of the canvas. |  | ||||||
|         /// </summary> |  | ||||||
|         public int PixelWidth { get; set; } = 2; |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Gets or sets the <see cref="IResampler"/> that should |  | ||||||
|         /// be used when scaling the image. Defaults to bicubic sampling. |  | ||||||
|         /// </summary> |  | ||||||
|         public IResampler? Resampler { get; set; } |  | ||||||
|  |  | ||||||
|         internal SixLabors.ImageSharp.Image<Rgba32> Image { get; } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Initializes a new instance of the <see cref="CanvasImage"/> class. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="filename">The image filename.</param> |  | ||||||
|         public CanvasImage(string filename) |  | ||||||
|         { |  | ||||||
|             Image = SixLabors.ImageSharp.Image.Load<Rgba32>(filename); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Initializes a new instance of the <see cref="CanvasImage"/> class. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="data">Buffer containing an image.</param> |  | ||||||
|         public CanvasImage(ReadOnlySpan<byte> data) |  | ||||||
|         { |  | ||||||
|             Image = SixLabors.ImageSharp.Image.Load<Rgba32>(data); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Initializes a new instance of the <see cref="CanvasImage"/> class. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="data">Stream containing an image.</param> |  | ||||||
|         public CanvasImage(Stream data) |  | ||||||
|         { |  | ||||||
|             Image = SixLabors.ImageSharp.Image.Load<Rgba32>(data); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         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); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         protected override IEnumerable<Segment> 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); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Initializes a new instance of the <see cref="CanvasImage"/> class. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="data">Buffer containing an image.</param> | ||||||
|  |     public CanvasImage(ReadOnlySpan<byte> data) | ||||||
|  |     { | ||||||
|  |         Image = SixLabors.ImageSharp.Image.Load<Rgba32>(data); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Initializes a new instance of the <see cref="CanvasImage"/> class. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="data">Stream containing an image.</param> | ||||||
|  |     public CanvasImage(Stream data) | ||||||
|  |     { | ||||||
|  |         Image = SixLabors.ImageSharp.Image.Load<Rgba32>(data); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <inheritdoc/> | ||||||
|  |     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); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <inheritdoc/> | ||||||
|  |     protected override IEnumerable<Segment> 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); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,135 +1,134 @@ | |||||||
| using System; | using System; | ||||||
| using SixLabors.ImageSharp.Processing; | using SixLabors.ImageSharp.Processing; | ||||||
|  |  | ||||||
| namespace Spectre.Console | namespace Spectre.Console; | ||||||
|  |  | ||||||
|  | /// <summary> | ||||||
|  | /// Contains extension methods for <see cref="CanvasImage"/>. | ||||||
|  | /// </summary> | ||||||
|  | public static class CanvasImageExtensions | ||||||
| { | { | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// Contains extension methods for <see cref="CanvasImage"/>. |     /// Sets the maximum width of the rendered image. | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     public static class CanvasImageExtensions |     /// <param name="image">The canvas image.</param> | ||||||
|  |     /// <param name="maxWidth">The maximum width.</param> | ||||||
|  |     /// <returns>The same instance so that multiple calls can be chained.</returns> | ||||||
|  |     public static CanvasImage MaxWidth(this CanvasImage image, int? maxWidth) | ||||||
|     { |     { | ||||||
|         /// <summary> |         if (image is null) | ||||||
|         /// Sets the maximum width of the rendered image. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="image">The canvas image.</param> |  | ||||||
|         /// <param name="maxWidth">The maximum width.</param> |  | ||||||
|         /// <returns>The same instance so that multiple calls can be chained.</returns> |  | ||||||
|         public static CanvasImage MaxWidth(this CanvasImage image, int? maxWidth) |  | ||||||
|         { |         { | ||||||
|             if (image is null) |             throw new ArgumentNullException(nameof(image)); | ||||||
|             { |  | ||||||
|                 throw new ArgumentNullException(nameof(image)); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             image.MaxWidth = maxWidth; |  | ||||||
|             return image; |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         /// <summary> |         image.MaxWidth = maxWidth; | ||||||
|         /// Disables the maximum width of the rendered image. |         return image; | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="image">The canvas image.</param> |  | ||||||
|         /// <returns>The same instance so that multiple calls can be chained.</returns> |  | ||||||
|         public static CanvasImage NoMaxWidth(this CanvasImage image) |  | ||||||
|         { |  | ||||||
|             if (image is null) |  | ||||||
|             { |  | ||||||
|                 throw new ArgumentNullException(nameof(image)); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             image.MaxWidth = null; |  | ||||||
|             return image; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Sets the pixel width. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="image">The canvas image.</param> |  | ||||||
|         /// <param name="width">The pixel width.</param> |  | ||||||
|         /// <returns>The same instance so that multiple calls can be chained.</returns> |  | ||||||
|         public static CanvasImage PixelWidth(this CanvasImage image, int width) |  | ||||||
|         { |  | ||||||
|             if (image is null) |  | ||||||
|             { |  | ||||||
|                 throw new ArgumentNullException(nameof(image)); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             image.PixelWidth = width; |  | ||||||
|             return image; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Mutates the underlying image. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="image">The canvas image.</param> |  | ||||||
|         /// <param name="action">The action that mutates the underlying image.</param> |  | ||||||
|         /// <returns>The same instance so that multiple calls can be chained.</returns> |  | ||||||
|         public static CanvasImage Mutate(this CanvasImage image, Action<IImageProcessingContext> 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; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Uses a bicubic sampler that implements the bicubic kernel algorithm W(x). |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="image">The canvas image.</param> |  | ||||||
|         /// <returns>The same instance so that multiple calls can be chained.</returns> |  | ||||||
|         public static CanvasImage BicubicResampler(this CanvasImage image) |  | ||||||
|         { |  | ||||||
|             if (image is null) |  | ||||||
|             { |  | ||||||
|                 throw new ArgumentNullException(nameof(image)); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             image.Resampler = KnownResamplers.Bicubic; |  | ||||||
|             return image; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 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. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="image">The canvas image.</param> |  | ||||||
|         /// <returns>The same instance so that multiple calls can be chained.</returns> |  | ||||||
|         public static CanvasImage BilinearResampler(this CanvasImage image) |  | ||||||
|         { |  | ||||||
|             if (image is null) |  | ||||||
|             { |  | ||||||
|                 throw new ArgumentNullException(nameof(image)); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             image.Resampler = KnownResamplers.Triangle; |  | ||||||
|             return image; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// 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. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="image">The canvas image.</param> |  | ||||||
|         /// <returns>The same instance so that multiple calls can be chained.</returns> |  | ||||||
|         public static CanvasImage NearestNeighborResampler(this CanvasImage image) |  | ||||||
|         { |  | ||||||
|             if (image is null) |  | ||||||
|             { |  | ||||||
|                 throw new ArgumentNullException(nameof(image)); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             image.Resampler = KnownResamplers.NearestNeighbor; |  | ||||||
|             return image; |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Disables the maximum width of the rendered image. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="image">The canvas image.</param> | ||||||
|  |     /// <returns>The same instance so that multiple calls can be chained.</returns> | ||||||
|  |     public static CanvasImage NoMaxWidth(this CanvasImage image) | ||||||
|  |     { | ||||||
|  |         if (image is null) | ||||||
|  |         { | ||||||
|  |             throw new ArgumentNullException(nameof(image)); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         image.MaxWidth = null; | ||||||
|  |         return image; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Sets the pixel width. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="image">The canvas image.</param> | ||||||
|  |     /// <param name="width">The pixel width.</param> | ||||||
|  |     /// <returns>The same instance so that multiple calls can be chained.</returns> | ||||||
|  |     public static CanvasImage PixelWidth(this CanvasImage image, int width) | ||||||
|  |     { | ||||||
|  |         if (image is null) | ||||||
|  |         { | ||||||
|  |             throw new ArgumentNullException(nameof(image)); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         image.PixelWidth = width; | ||||||
|  |         return image; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Mutates the underlying image. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="image">The canvas image.</param> | ||||||
|  |     /// <param name="action">The action that mutates the underlying image.</param> | ||||||
|  |     /// <returns>The same instance so that multiple calls can be chained.</returns> | ||||||
|  |     public static CanvasImage Mutate(this CanvasImage image, Action<IImageProcessingContext> 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; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Uses a bicubic sampler that implements the bicubic kernel algorithm W(x). | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="image">The canvas image.</param> | ||||||
|  |     /// <returns>The same instance so that multiple calls can be chained.</returns> | ||||||
|  |     public static CanvasImage BicubicResampler(this CanvasImage image) | ||||||
|  |     { | ||||||
|  |         if (image is null) | ||||||
|  |         { | ||||||
|  |             throw new ArgumentNullException(nameof(image)); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         image.Resampler = KnownResamplers.Bicubic; | ||||||
|  |         return image; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// 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. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="image">The canvas image.</param> | ||||||
|  |     /// <returns>The same instance so that multiple calls can be chained.</returns> | ||||||
|  |     public static CanvasImage BilinearResampler(this CanvasImage image) | ||||||
|  |     { | ||||||
|  |         if (image is null) | ||||||
|  |         { | ||||||
|  |             throw new ArgumentNullException(nameof(image)); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         image.Resampler = KnownResamplers.Triangle; | ||||||
|  |         return image; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// 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. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="image">The canvas image.</param> | ||||||
|  |     /// <returns>The same instance so that multiple calls can be chained.</returns> | ||||||
|  |     public static CanvasImage NearestNeighborResampler(this CanvasImage image) | ||||||
|  |     { | ||||||
|  |         if (image is null) | ||||||
|  |         { | ||||||
|  |             throw new ArgumentNullException(nameof(image)); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         image.Resampler = KnownResamplers.NearestNeighbor; | ||||||
|  |         return image; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,28 +1,27 @@ | |||||||
| using System; | using System; | ||||||
| using Spectre.Console.Cli; | using Spectre.Console.Cli; | ||||||
|  |  | ||||||
| namespace Spectre.Console.Testing | namespace Spectre.Console.Testing; | ||||||
|  |  | ||||||
|  | /// <summary> | ||||||
|  | /// A <see cref="ICommandInterceptor"/> that triggers a callback when invoked. | ||||||
|  | /// </summary> | ||||||
|  | public sealed class CallbackCommandInterceptor : ICommandInterceptor | ||||||
| { | { | ||||||
|  |     private readonly Action<CommandContext, CommandSettings> _callback; | ||||||
|  |  | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// A <see cref="ICommandInterceptor"/> that triggers a callback when invoked. |     /// Initializes a new instance of the <see cref="CallbackCommandInterceptor"/> class. | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     public sealed class CallbackCommandInterceptor : ICommandInterceptor |     /// <param name="callback">The callback to call when the interceptor is invoked.</param> | ||||||
|  |     public CallbackCommandInterceptor(Action<CommandContext, CommandSettings> callback) | ||||||
|     { |     { | ||||||
|         private readonly Action<CommandContext, CommandSettings> _callback; |         _callback = callback ?? throw new ArgumentNullException(nameof(callback)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|         /// <summary> |     /// <inheritdoc/> | ||||||
|         /// Initializes a new instance of the <see cref="CallbackCommandInterceptor"/> class. |     public void Intercept(CommandContext context, CommandSettings settings) | ||||||
|         /// </summary> |     { | ||||||
|         /// <param name="callback">The callback to call when the interceptor is invoked.</param> |         _callback(context, settings); | ||||||
|         public CallbackCommandInterceptor(Action<CommandContext, CommandSettings> callback) |  | ||||||
|         { |  | ||||||
|             _callback = callback ?? throw new ArgumentNullException(nameof(callback)); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         public void Intercept(CommandContext context, CommandSettings settings) |  | ||||||
|         { |  | ||||||
|             _callback(context, settings); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,29 +1,28 @@ | |||||||
| using System; | using System; | ||||||
| using Spectre.Console.Cli; | using Spectre.Console.Cli; | ||||||
|  |  | ||||||
| namespace Spectre.Console.Testing | namespace Spectre.Console.Testing; | ||||||
|  |  | ||||||
|  | /// <summary> | ||||||
|  | /// Represents a <see cref="CommandApp"/> runtime failure. | ||||||
|  | /// </summary> | ||||||
|  | public sealed class CommandAppFailure | ||||||
| { | { | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// Represents a <see cref="CommandApp"/> runtime failure. |     /// Gets the exception that was thrown. | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     public sealed class CommandAppFailure |     public Exception Exception { get; } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Gets the console output. | ||||||
|  |     /// </summary> | ||||||
|  |     public string Output { get; } | ||||||
|  |  | ||||||
|  |     internal CommandAppFailure(Exception exception, string output) | ||||||
|     { |     { | ||||||
|         /// <summary> |         Exception = exception ?? throw new ArgumentNullException(nameof(exception)); | ||||||
|         /// Gets the exception that was thrown. |         Output = output.NormalizeLineEndings() | ||||||
|         /// </summary> |             .TrimLines() | ||||||
|         public Exception Exception { get; } |             .Trim(); | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Gets the console output. |  | ||||||
|         /// </summary> |  | ||||||
|         public string Output { get; } |  | ||||||
|  |  | ||||||
|         internal CommandAppFailure(Exception exception, string output) |  | ||||||
|         { |  | ||||||
|             Exception = exception ?? throw new ArgumentNullException(nameof(exception)); |  | ||||||
|             Output = output.NormalizeLineEndings() |  | ||||||
|                 .TrimLines() |  | ||||||
|                 .Trim(); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,43 +1,42 @@ | |||||||
| using Spectre.Console.Cli; | using Spectre.Console.Cli; | ||||||
|  |  | ||||||
| namespace Spectre.Console.Testing | namespace Spectre.Console.Testing; | ||||||
|  |  | ||||||
|  | /// <summary> | ||||||
|  | /// Represents the result of a completed <see cref="CommandApp"/> run. | ||||||
|  | /// </summary> | ||||||
|  | public sealed class CommandAppResult | ||||||
| { | { | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// Represents the result of a completed <see cref="CommandApp"/> run. |     /// Gets the exit code. | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     public sealed class CommandAppResult |     public int ExitCode { get; } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Gets the console output. | ||||||
|  |     /// </summary> | ||||||
|  |     public string Output { get; } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Gets the command context. | ||||||
|  |     /// </summary> | ||||||
|  |     public CommandContext? Context { get; } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Gets the command settings. | ||||||
|  |     /// </summary> | ||||||
|  |     public CommandSettings? Settings { get; } | ||||||
|  |  | ||||||
|  |     internal CommandAppResult(int exitCode, string output, CommandContext? context, CommandSettings? settings) | ||||||
|     { |     { | ||||||
|         /// <summary> |         ExitCode = exitCode; | ||||||
|         /// Gets the exit code. |         Output = output ?? string.Empty; | ||||||
|         /// </summary> |         Context = context; | ||||||
|         public int ExitCode { get; } |         Settings = settings; | ||||||
|  |  | ||||||
|         /// <summary> |         Output = Output | ||||||
|         /// Gets the console output. |             .NormalizeLineEndings() | ||||||
|         /// </summary> |             .TrimLines() | ||||||
|         public string Output { get; } |             .Trim(); | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Gets the command context. |  | ||||||
|         /// </summary> |  | ||||||
|         public CommandContext? Context { get; } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Gets the command settings. |  | ||||||
|         /// </summary> |  | ||||||
|         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(); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,135 +1,134 @@ | |||||||
| using System; | using System; | ||||||
| using Spectre.Console.Cli; | using Spectre.Console.Cli; | ||||||
|  |  | ||||||
| namespace Spectre.Console.Testing | namespace Spectre.Console.Testing; | ||||||
|  |  | ||||||
|  | /// <summary> | ||||||
|  | /// A <see cref="CommandApp"/> test harness. | ||||||
|  | /// </summary> | ||||||
|  | public sealed class CommandAppTester | ||||||
| { | { | ||||||
|  |     private Action<CommandApp>? _appConfiguration; | ||||||
|  |     private Action<IConfigurator>? _configuration; | ||||||
|  |  | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// A <see cref="CommandApp"/> test harness. |     /// Initializes a new instance of the <see cref="CommandAppTester"/> class. | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     public sealed class CommandAppTester |     /// <param name="registrar">The registrar.</param> | ||||||
|  |     public CommandAppTester(ITypeRegistrar? registrar = null) | ||||||
|     { |     { | ||||||
|         private Action<CommandApp>? _appConfiguration; |         Registrar = registrar; | ||||||
|         private Action<IConfigurator>? _configuration; |     } | ||||||
|  |  | ||||||
|         /// <summary> |     /// <summary> | ||||||
|         /// Initializes a new instance of the <see cref="CommandAppTester"/> class. |     /// Gets or sets the Registrar to use in the CommandApp. | ||||||
|         /// </summary> |     /// </summary> | ||||||
|         /// <param name="registrar">The registrar.</param> |     public ITypeRegistrar? Registrar { get; set; } | ||||||
|         public CommandAppTester(ITypeRegistrar? registrar = null) |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Sets the default command. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <typeparam name="T">The default command type.</typeparam> | ||||||
|  |     public void SetDefaultCommand<T>() | ||||||
|  |         where T : class, ICommand | ||||||
|  |     { | ||||||
|  |         _appConfiguration = (app) => app.SetDefaultCommand<T>(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Configures the command application. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="action">The configuration action.</param> | ||||||
|  |     public void Configure(Action<IConfigurator> action) | ||||||
|  |     { | ||||||
|  |         if (_configuration != null) | ||||||
|         { |         { | ||||||
|             Registrar = registrar; |             throw new InvalidOperationException("The command app harnest have already been configured."); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         /// <summary> |         _configuration = action; | ||||||
|         /// Gets or sets the Registrar to use in the CommandApp. |     } | ||||||
|         /// </summary> |  | ||||||
|         public ITypeRegistrar? Registrar { get; set; } |  | ||||||
|  |  | ||||||
|         /// <summary> |     /// <summary> | ||||||
|         /// Sets the default command. |     /// Runs the command application and expects an exception of a specific type to be thrown. | ||||||
|         /// </summary> |     /// </summary> | ||||||
|         /// <typeparam name="T">The default command type.</typeparam> |     /// <typeparam name="T">The expected exception type.</typeparam> | ||||||
|         public void SetDefaultCommand<T>() |     /// <param name="args">The arguments.</param> | ||||||
|             where T : class, ICommand |     /// <returns>The information about the failure.</returns> | ||||||
|  |     public CommandAppFailure RunAndCatch<T>(params string[] args) | ||||||
|  |         where T : Exception | ||||||
|  |     { | ||||||
|  |         var console = new TestConsole().Width(int.MaxValue); | ||||||
|  |  | ||||||
|  |         try | ||||||
|         { |         { | ||||||
|             _appConfiguration = (app) => app.SetDefaultCommand<T>(); |             Run(args, console, c => c.PropagateExceptions()); | ||||||
|  |             throw new InvalidOperationException("Expected an exception to be thrown, but there was none."); | ||||||
|         } |         } | ||||||
|  |         catch (T ex) | ||||||
|         /// <summary> |  | ||||||
|         /// Configures the command application. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="action">The configuration action.</param> |  | ||||||
|         public void Configure(Action<IConfigurator> action) |  | ||||||
|         { |         { | ||||||
|             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); | ||||||
|         } |         } | ||||||
|  |         catch (Exception ex) | ||||||
|         /// <summary> |  | ||||||
|         /// Runs the command application and expects an exception of a specific type to be thrown. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <typeparam name="T">The expected exception type.</typeparam> |  | ||||||
|         /// <param name="args">The arguments.</param> |  | ||||||
|         /// <returns>The information about the failure.</returns> |  | ||||||
|         public CommandAppFailure RunAndCatch<T>(params string[] args) |  | ||||||
|             where T : Exception |  | ||||||
|         { |         { | ||||||
|             var console = new TestConsole().Width(int.MaxValue); |             throw new InvalidOperationException( | ||||||
|  |                 $"Expected an exception of type '{typeof(T).FullName}' to be thrown, " | ||||||
|             try |                 + $"but received {ex.GetType().FullName}."); | ||||||
|             { |  | ||||||
|                 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}."); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Runs the command application. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="args">The arguments.</param> |  | ||||||
|         /// <returns>The result.</returns> |  | ||||||
|         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<IConfigurator>? 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); |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Runs the command application. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="args">The arguments.</param> | ||||||
|  |     /// <returns>The result.</returns> | ||||||
|  |     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<IConfigurator>? 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); | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,191 +1,190 @@ | |||||||
| using System; | using System; | ||||||
| using Spectre.Console.Cli; | using Spectre.Console.Cli; | ||||||
|  |  | ||||||
| namespace Spectre.Console.Testing | namespace Spectre.Console.Testing; | ||||||
|  |  | ||||||
|  | /// <summary> | ||||||
|  | /// This is a utility class for implementors of | ||||||
|  | /// <see cref="ITypeRegistrar"/> and corresponding <see cref="ITypeResolver"/>. | ||||||
|  | /// </summary> | ||||||
|  | public sealed class TypeRegistrarBaseTests | ||||||
| { | { | ||||||
|  |     private readonly Func<ITypeRegistrar> _registrarFactory; | ||||||
|  |  | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// This is a utility class for implementors of |     /// Initializes a new instance of the <see cref="TypeRegistrarBaseTests"/> class. | ||||||
|     /// <see cref="ITypeRegistrar"/> and corresponding <see cref="ITypeResolver"/>. |  | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     public sealed class TypeRegistrarBaseTests |     /// <param name="registrarFactory">The factory to create a new, clean <see cref="ITypeRegistrar"/> to be used for each test.</param> | ||||||
|  |     public TypeRegistrarBaseTests(Func<ITypeRegistrar> registrarFactory) | ||||||
|     { |     { | ||||||
|         private readonly Func<ITypeRegistrar> _registrarFactory; |         _registrarFactory = registrarFactory; | ||||||
|  |     } | ||||||
|  |  | ||||||
|         /// <summary> |     /// <summary> | ||||||
|         /// Initializes a new instance of the <see cref="TypeRegistrarBaseTests"/> class. |     /// Runs all tests. | ||||||
|         /// </summary> |     /// </summary> | ||||||
|         /// <param name="registrarFactory">The factory to create a new, clean <see cref="ITypeRegistrar"/> to be used for each test.</param> |     /// <exception cref="TestFailedException">This exception is raised, if a test fails.</exception> | ||||||
|         public TypeRegistrarBaseTests(Func<ITypeRegistrar> registrarFactory) |     public void RunAllTests() | ||||||
|  |     { | ||||||
|  |         var testCases = new Action<ITypeRegistrar>[] | ||||||
|         { |         { | ||||||
|             _registrarFactory = registrarFactory; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Runs all tests. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <exception cref="TestFailedException">This exception is raised, if a test fails.</exception> |  | ||||||
|         public void RunAllTests() |  | ||||||
|         { |  | ||||||
|             var testCases = new Action<ITypeRegistrar>[] |  | ||||||
|             { |  | ||||||
|                 RegistrationsCanBeResolved, |                 RegistrationsCanBeResolved, | ||||||
|                 InstanceRegistrationsCanBeResolved, |                 InstanceRegistrationsCanBeResolved, | ||||||
|                 LazyRegistrationsCanBeResolved, |                 LazyRegistrationsCanBeResolved, | ||||||
|                 ResolvingNotRegisteredServiceReturnsNull, |                 ResolvingNotRegisteredServiceReturnsNull, | ||||||
|                 ResolvingNullTypeReturnsNull, |                 ResolvingNullTypeReturnsNull, | ||||||
|             }; |         }; | ||||||
|  |  | ||||||
|             foreach (var test in testCases) |         foreach (var test in testCases) | ||||||
|             { |  | ||||||
|                 test(_registrarFactory()); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         private static void ResolvingNullTypeReturnsNull(ITypeRegistrar registrar) |  | ||||||
|         { |         { | ||||||
|             // Given no registration |             test(_registrarFactory()); | ||||||
|             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."); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// internal use only. |  | ||||||
|         /// </summary> |  | ||||||
|         private interface IMockService |  | ||||||
|         { |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         private class MockService : IMockService |  | ||||||
|         { |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Exception, to be raised when a test fails. |  | ||||||
|         /// </summary> |  | ||||||
|         public sealed class TestFailedException : Exception |  | ||||||
|         { |  | ||||||
|             /// <inheritdoc cref="Exception" /> |  | ||||||
|             public TestFailedException(string message) |  | ||||||
|                 : base(message) |  | ||||||
|             { |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             /// <inheritdoc cref="Exception" /> |  | ||||||
|             public TestFailedException(string message, Exception inner) |  | ||||||
|                 : base(message, inner) |  | ||||||
|             { |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } |  | ||||||
|  |     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."); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// internal use only. | ||||||
|  |     /// </summary> | ||||||
|  |     private interface IMockService | ||||||
|  |     { | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private class MockService : IMockService | ||||||
|  |     { | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Exception, to be raised when a test fails. | ||||||
|  |     /// </summary> | ||||||
|  |     public sealed class TestFailedException : Exception | ||||||
|  |     { | ||||||
|  |         /// <inheritdoc cref="Exception" /> | ||||||
|  |         public TestFailedException(string message) | ||||||
|  |             : base(message) | ||||||
|  |         { | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /// <inheritdoc cref="Exception" /> | ||||||
|  |         public TestFailedException(string message, Exception inner) | ||||||
|  |             : base(message, inner) | ||||||
|  |         { | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|   | |||||||
| @@ -1,47 +1,46 @@ | |||||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||||
|  |  | ||||||
| namespace Spectre.Console.Testing | namespace Spectre.Console.Testing; | ||||||
|  |  | ||||||
|  | /// <summary> | ||||||
|  | /// Contains extensions for <see cref="string"/>. | ||||||
|  | /// </summary> | ||||||
|  | public static class StringExtensions | ||||||
| { | { | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// Contains extensions for <see cref="string"/>. |     /// Returns a new string with all lines trimmed of trailing whitespace. | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     public static class StringExtensions |     /// <param name="value">The string to trim.</param> | ||||||
|  |     /// <returns>A new string with all lines trimmed of trailing whitespace.</returns> | ||||||
|  |     public static string TrimLines(this string value) | ||||||
|     { |     { | ||||||
|         /// <summary> |         if (value is null) | ||||||
|         /// Returns a new string with all lines trimmed of trailing whitespace. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="value">The string to trim.</param> |  | ||||||
|         /// <returns>A new string with all lines trimmed of trailing whitespace.</returns> |  | ||||||
|         public static string TrimLines(this string value) |  | ||||||
|         { |         { | ||||||
|             if (value is null) |  | ||||||
|             { |  | ||||||
|                 return string.Empty; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             var result = new List<string>(); |  | ||||||
|             foreach (var line in value.NormalizeLineEndings().Split(new[] { '\n' })) |  | ||||||
|             { |  | ||||||
|                 result.Add(line.TrimEnd()); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             return string.Join("\n", result); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Returns a new string with normalized line endings. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="value">The string to normalize line endings for.</param> |  | ||||||
|         /// <returns>A new string with normalized line endings.</returns> |  | ||||||
|         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; |             return string.Empty; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         var result = new List<string>(); | ||||||
|  |         foreach (var line in value.NormalizeLineEndings().Split(new[] { '\n' })) | ||||||
|  |         { | ||||||
|  |             result.Add(line.TrimEnd()); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return string.Join("\n", result); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Returns a new string with normalized line endings. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="value">The string to normalize line endings for.</param> | ||||||
|  |     /// <returns>A new string with normalized line endings.</returns> | ||||||
|  |     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; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,25 +1,24 @@ | |||||||
| namespace Spectre.Console.Testing | namespace Spectre.Console.Testing; | ||||||
|  |  | ||||||
|  | /// <summary> | ||||||
|  | /// Contains extensions for <see cref="Style"/>. | ||||||
|  | /// </summary> | ||||||
|  | public static class StyleExtensions | ||||||
| { | { | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// Contains extensions for <see cref="Style"/>. |     /// Sets the foreground or background color of the specified style. | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     public static class StyleExtensions |     /// <param name="style">The style.</param> | ||||||
|  |     /// <param name="color">The color.</param> | ||||||
|  |     /// <param name="foreground">Whether or not to set the foreground color.</param> | ||||||
|  |     /// <returns>The same instance so that multiple calls can be chained.</returns> | ||||||
|  |     public static Style SetColor(this Style style, Color color, bool foreground) | ||||||
|     { |     { | ||||||
|         /// <summary> |         if (foreground) | ||||||
|         /// Sets the foreground or background color of the specified style. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="style">The style.</param> |  | ||||||
|         /// <param name="color">The color.</param> |  | ||||||
|         /// <param name="foreground">Whether or not to set the foreground color.</param> |  | ||||||
|         /// <returns>The same instance so that multiple calls can be chained.</returns> |  | ||||||
|         public static Style SetColor(this Style style, Color color, bool foreground) |  | ||||||
|         { |         { | ||||||
|             if (foreground) |             return style.Foreground(color); | ||||||
|             { |  | ||||||
|                 return style.Foreground(color); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             return style.Background(color); |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         return style.Background(color); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -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) | ||||||
|         { |     { | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,18 +1,17 @@ | |||||||
| using System; | using System; | ||||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||||
|  |  | ||||||
| namespace Spectre.Console.Testing | namespace Spectre.Console.Testing; | ||||||
| { |  | ||||||
|     internal sealed class NoopExclusivityMode : IExclusivityMode |  | ||||||
|     { |  | ||||||
|         public T Run<T>(Func<T> func) |  | ||||||
|         { |  | ||||||
|             return func(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         public async Task<T> RunAsync<T>(Func<Task<T>> func) | internal sealed class NoopExclusivityMode : IExclusivityMode | ||||||
|         { | { | ||||||
|             return await func().ConfigureAwait(false); |     public T Run<T>(Func<T> func) | ||||||
|         } |     { | ||||||
|  |         return func(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public async Task<T> RunAsync<T>(Func<Task<T>> func) | ||||||
|  |     { | ||||||
|  |         return await func().ConfigureAwait(false); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,40 +1,39 @@ | |||||||
| using Spectre.Console.Rendering; | using Spectre.Console.Rendering; | ||||||
|  |  | ||||||
| namespace Spectre.Console.Testing | namespace Spectre.Console.Testing; | ||||||
|  |  | ||||||
|  | /// <summary> | ||||||
|  | /// Represents fake capabilities useful in tests. | ||||||
|  | /// </summary> | ||||||
|  | public sealed class TestCapabilities : IReadOnlyCapabilities | ||||||
| { | { | ||||||
|  |     /// <inheritdoc/> | ||||||
|  |     public ColorSystem ColorSystem { get; set; } = ColorSystem.TrueColor; | ||||||
|  |  | ||||||
|  |     /// <inheritdoc/> | ||||||
|  |     public bool Ansi { get; set; } | ||||||
|  |  | ||||||
|  |     /// <inheritdoc/> | ||||||
|  |     public bool Links { get; set; } | ||||||
|  |  | ||||||
|  |     /// <inheritdoc/> | ||||||
|  |     public bool Legacy { get; set; } | ||||||
|  |  | ||||||
|  |     /// <inheritdoc/> | ||||||
|  |     public bool IsTerminal { get; set; } | ||||||
|  |  | ||||||
|  |     /// <inheritdoc/> | ||||||
|  |     public bool Interactive { get; set; } | ||||||
|  |  | ||||||
|  |     /// <inheritdoc/> | ||||||
|  |     public bool Unicode { get; set; } | ||||||
|  |  | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// Represents fake capabilities useful in tests. |     /// Creates a <see cref="RenderContext"/> with the same capabilities as this instace. | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     public sealed class TestCapabilities : IReadOnlyCapabilities |     /// <returns>A <see cref="RenderContext"/> with the same capabilities as this instace.</returns> | ||||||
|  |     public RenderContext CreateRenderContext() | ||||||
|     { |     { | ||||||
|         /// <inheritdoc/> |         return new RenderContext(this); | ||||||
|         public ColorSystem ColorSystem { get; set; } = ColorSystem.TrueColor; |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         public bool Ansi { get; set; } |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         public bool Links { get; set; } |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         public bool Legacy { get; set; } |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         public bool IsTerminal { get; set; } |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         public bool Interactive { get; set; } |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         public bool Unicode { get; set; } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Creates a <see cref="RenderContext"/> with the same capabilities as this instace. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <returns>A <see cref="RenderContext"/> with the same capabilities as this instace.</returns> |  | ||||||
|         public RenderContext CreateRenderContext() |  | ||||||
|         { |  | ||||||
|             return new RenderContext(this); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -3,120 +3,119 @@ using System.Collections.Generic; | |||||||
| using System.IO; | using System.IO; | ||||||
| using Spectre.Console.Rendering; | using Spectre.Console.Rendering; | ||||||
|  |  | ||||||
| namespace Spectre.Console.Testing | namespace Spectre.Console.Testing; | ||||||
|  |  | ||||||
|  | /// <summary> | ||||||
|  | /// A testable console. | ||||||
|  | /// </summary> | ||||||
|  | public sealed class TestConsole : IAnsiConsole, IDisposable | ||||||
| { | { | ||||||
|  |     private readonly IAnsiConsole _console; | ||||||
|  |     private readonly StringWriter _writer; | ||||||
|  |     private IAnsiConsoleCursor? _cursor; | ||||||
|  |  | ||||||
|  |     /// <inheritdoc/> | ||||||
|  |     public Profile Profile => _console.Profile; | ||||||
|  |  | ||||||
|  |     /// <inheritdoc/> | ||||||
|  |     public IExclusivityMode ExclusivityMode => _console.ExclusivityMode; | ||||||
|  |  | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// A testable console. |     /// Gets the console input. | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     public sealed class TestConsole : IAnsiConsole, IDisposable |     public TestConsoleInput Input { get; } | ||||||
|  |  | ||||||
|  |     /// <inheritdoc/> | ||||||
|  |     public RenderPipeline Pipeline => _console.Pipeline; | ||||||
|  |  | ||||||
|  |     /// <inheritdoc/> | ||||||
|  |     public IAnsiConsoleCursor Cursor => _cursor ?? _console.Cursor; | ||||||
|  |  | ||||||
|  |     /// <inheritdoc/> | ||||||
|  |     IAnsiConsoleInput IAnsiConsole.Input => Input; | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Gets the console output. | ||||||
|  |     /// </summary> | ||||||
|  |     public string Output => _writer.ToString(); | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Gets the console output lines. | ||||||
|  |     /// </summary> | ||||||
|  |     public IReadOnlyList<string> Lines => Output.NormalizeLineEndings().TrimEnd('\n').Split(new char[] { '\n' }); | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Gets or sets a value indicating whether or not VT/ANSI sequences | ||||||
|  |     /// should be emitted to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     public bool EmitAnsiSequences { get; set; } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Initializes a new instance of the <see cref="TestConsole"/> class. | ||||||
|  |     /// </summary> | ||||||
|  |     public TestConsole() | ||||||
|     { |     { | ||||||
|         private readonly IAnsiConsole _console; |         _writer = new StringWriter(); | ||||||
|         private readonly StringWriter _writer; |         _cursor = new NoopCursor(); | ||||||
|         private IAnsiConsoleCursor? _cursor; |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |         Input = new TestConsoleInput(); | ||||||
|         public Profile Profile => _console.Profile; |         EmitAnsiSequences = false; | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |         var factory = new AnsiConsoleFactory(); | ||||||
|         public IExclusivityMode ExclusivityMode => _console.ExclusivityMode; |         _console = factory.Create(new AnsiConsoleSettings | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Gets the console input. |  | ||||||
|         /// </summary> |  | ||||||
|         public TestConsoleInput Input { get; } |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         public RenderPipeline Pipeline => _console.Pipeline; |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         public IAnsiConsoleCursor Cursor => _cursor ?? _console.Cursor; |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         IAnsiConsoleInput IAnsiConsole.Input => Input; |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Gets the console output. |  | ||||||
|         /// </summary> |  | ||||||
|         public string Output => _writer.ToString(); |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Gets the console output lines. |  | ||||||
|         /// </summary> |  | ||||||
|         public IReadOnlyList<string> Lines => Output.NormalizeLineEndings().TrimEnd('\n').Split(new char[] { '\n' }); |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Gets or sets a value indicating whether or not VT/ANSI sequences |  | ||||||
|         /// should be emitted to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         public bool EmitAnsiSequences { get; set; } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Initializes a new instance of the <see cref="TestConsole"/> class. |  | ||||||
|         /// </summary> |  | ||||||
|         public TestConsole() |  | ||||||
|         { |         { | ||||||
|             _writer = new StringWriter(); |             Ansi = AnsiSupport.Yes, | ||||||
|             _cursor = new NoopCursor(); |             ColorSystem = (ColorSystemSupport)ColorSystem.TrueColor, | ||||||
|  |             Out = new AnsiConsoleOutput(_writer), | ||||||
|             Input = new TestConsoleInput(); |             Interactive = InteractionSupport.No, | ||||||
|             EmitAnsiSequences = false; |             ExclusivityMode = new NoopExclusivityMode(), | ||||||
|  |             Enrichment = new ProfileEnrichment | ||||||
|             var factory = new AnsiConsoleFactory(); |  | ||||||
|             _console = factory.Create(new AnsiConsoleSettings |  | ||||||
|             { |             { | ||||||
|                 Ansi = AnsiSupport.Yes, |                 UseDefaultEnrichers = false, | ||||||
|                 ColorSystem = (ColorSystemSupport)ColorSystem.TrueColor, |             }, | ||||||
|                 Out = new AnsiConsoleOutput(_writer), |         }); | ||||||
|                 Interactive = InteractionSupport.No, |  | ||||||
|                 ExclusivityMode = new NoopExclusivityMode(), |         _console.Profile.Width = 80; | ||||||
|                 Enrichment = new ProfileEnrichment |         _console.Profile.Height = 24; | ||||||
|  |         _console.Profile.Capabilities.Ansi = true; | ||||||
|  |         _console.Profile.Capabilities.Unicode = true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <inheritdoc/> | ||||||
|  |     public void Dispose() | ||||||
|  |     { | ||||||
|  |         _writer.Dispose(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <inheritdoc/> | ||||||
|  |     public void Clear(bool home) | ||||||
|  |     { | ||||||
|  |         _console.Clear(home); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <inheritdoc/> | ||||||
|  |     public void Write(IRenderable renderable) | ||||||
|  |     { | ||||||
|  |         if (EmitAnsiSequences) | ||||||
|  |         { | ||||||
|  |             _console.Write(renderable); | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             foreach (var segment in renderable.GetSegments(this)) | ||||||
|  |             { | ||||||
|  |                 if (segment.IsControlCode) | ||||||
|                 { |                 { | ||||||
|                     UseDefaultEnrichers = false, |                     continue; | ||||||
|                 }, |  | ||||||
|             }); |  | ||||||
|  |  | ||||||
|             _console.Profile.Width = 80; |  | ||||||
|             _console.Profile.Height = 24; |  | ||||||
|             _console.Profile.Capabilities.Ansi = true; |  | ||||||
|             _console.Profile.Capabilities.Unicode = true; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         public void Dispose() |  | ||||||
|         { |  | ||||||
|             _writer.Dispose(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         public void Clear(bool home) |  | ||||||
|         { |  | ||||||
|             _console.Clear(home); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         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); |  | ||||||
|                 } |                 } | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         internal void SetCursor(IAnsiConsoleCursor? cursor) |                 Profile.Out.Writer.Write(segment.Text); | ||||||
|         { |             } | ||||||
|             _cursor = cursor; |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     internal void SetCursor(IAnsiConsoleCursor? cursor) | ||||||
|  |     { | ||||||
|  |         _cursor = cursor; | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,67 +1,66 @@ | |||||||
| namespace Spectre.Console.Testing | namespace Spectre.Console.Testing; | ||||||
|  |  | ||||||
|  | /// <summary> | ||||||
|  | /// Contains extensions for <see cref="TestConsole"/>. | ||||||
|  | /// </summary> | ||||||
|  | public static class TestConsoleExtensions | ||||||
| { | { | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// Contains extensions for <see cref="TestConsole"/>. |     /// Sets the console's color system. | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     public static class TestConsoleExtensions |     /// <param name="console">The console.</param> | ||||||
|  |     /// <param name="colors">The color system to use.</param> | ||||||
|  |     /// <returns>The same instance so that multiple calls can be chained.</returns> | ||||||
|  |     public static TestConsole Colors(this TestConsole console, ColorSystem colors) | ||||||
|     { |     { | ||||||
|         /// <summary> |         console.Profile.Capabilities.ColorSystem = colors; | ||||||
|         /// Sets the console's color system. |         return console; | ||||||
|         /// </summary> |     } | ||||||
|         /// <param name="console">The console.</param> |  | ||||||
|         /// <param name="colors">The color system to use.</param> |  | ||||||
|         /// <returns>The same instance so that multiple calls can be chained.</returns> |  | ||||||
|         public static TestConsole Colors(this TestConsole console, ColorSystem colors) |  | ||||||
|         { |  | ||||||
|             console.Profile.Capabilities.ColorSystem = colors; |  | ||||||
|             return console; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |     /// <summary> | ||||||
|         /// Sets whether or not ANSI is supported. |     /// Sets whether or not ANSI is supported. | ||||||
|         /// </summary> |     /// </summary> | ||||||
|         /// <param name="console">The console.</param> |     /// <param name="console">The console.</param> | ||||||
|         /// <param name="enable">Whether or not VT/ANSI control codes are supported.</param> |     /// <param name="enable">Whether or not VT/ANSI control codes are supported.</param> | ||||||
|         /// <returns>The same instance so that multiple calls can be chained.</returns> |     /// <returns>The same instance so that multiple calls can be chained.</returns> | ||||||
|         public static TestConsole SupportsAnsi(this TestConsole console, bool enable) |     public static TestConsole SupportsAnsi(this TestConsole console, bool enable) | ||||||
|         { |     { | ||||||
|             console.Profile.Capabilities.Ansi = enable; |         console.Profile.Capabilities.Ansi = enable; | ||||||
|             return console; |         return console; | ||||||
|         } |     } | ||||||
|  |  | ||||||
|         /// <summary> |     /// <summary> | ||||||
|         /// Makes the console interactive. |     /// Makes the console interactive. | ||||||
|         /// </summary> |     /// </summary> | ||||||
|         /// <param name="console">The console.</param> |     /// <param name="console">The console.</param> | ||||||
|         /// <returns>The same instance so that multiple calls can be chained.</returns> |     /// <returns>The same instance so that multiple calls can be chained.</returns> | ||||||
|         public static TestConsole Interactive(this TestConsole console) |     public static TestConsole Interactive(this TestConsole console) | ||||||
|         { |     { | ||||||
|             console.Profile.Capabilities.Interactive = true; |         console.Profile.Capabilities.Interactive = true; | ||||||
|             return console; |         return console; | ||||||
|         } |     } | ||||||
|  |  | ||||||
|         /// <summary> |     /// <summary> | ||||||
|         /// Sets the console width. |     /// Sets the console width. | ||||||
|         /// </summary> |     /// </summary> | ||||||
|         /// <param name="console">The console.</param> |     /// <param name="console">The console.</param> | ||||||
|         /// <param name="width">The console width.</param> |     /// <param name="width">The console width.</param> | ||||||
|         /// <returns>The same instance so that multiple calls can be chained.</returns> |     /// <returns>The same instance so that multiple calls can be chained.</returns> | ||||||
|         public static TestConsole Width(this TestConsole console, int width) |     public static TestConsole Width(this TestConsole console, int width) | ||||||
|         { |     { | ||||||
|             console.Profile.Width = width; |         console.Profile.Width = width; | ||||||
|             return console; |         return console; | ||||||
|         } |     } | ||||||
|  |  | ||||||
|         /// <summary> |     /// <summary> | ||||||
|         /// Turns on emitting of VT/ANSI sequences. |     /// Turns on emitting of VT/ANSI sequences. | ||||||
|         /// </summary> |     /// </summary> | ||||||
|         /// <param name="console">The console.</param> |     /// <param name="console">The console.</param> | ||||||
|         /// <returns>The same instance so that multiple calls can be chained.</returns> |     /// <returns>The same instance so that multiple calls can be chained.</returns> | ||||||
|         public static TestConsole EmitAnsiSequences(this TestConsole console) |     public static TestConsole EmitAnsiSequences(this TestConsole console) | ||||||
|         { |     { | ||||||
|             console.SetCursor(null); |         console.SetCursor(null); | ||||||
|             console.EmitAnsiSequences = true; |         console.EmitAnsiSequences = true; | ||||||
|             return console; |         return console; | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -3,90 +3,89 @@ using System.Collections.Generic; | |||||||
| using System.Threading; | using System.Threading; | ||||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||||
|  |  | ||||||
| namespace Spectre.Console.Testing | namespace Spectre.Console.Testing; | ||||||
|  |  | ||||||
|  | /// <summary> | ||||||
|  | /// Represents a testable console input mechanism. | ||||||
|  | /// </summary> | ||||||
|  | public sealed class TestConsoleInput : IAnsiConsoleInput | ||||||
| { | { | ||||||
|  |     private readonly Queue<ConsoleKeyInfo> _input; | ||||||
|  |  | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// Represents a testable console input mechanism. |     /// Initializes a new instance of the <see cref="TestConsoleInput"/> class. | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     public sealed class TestConsoleInput : IAnsiConsoleInput |     public TestConsoleInput() | ||||||
|     { |     { | ||||||
|         private readonly Queue<ConsoleKeyInfo> _input; |         _input = new Queue<ConsoleKeyInfo>(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|         /// <summary> |     /// <summary> | ||||||
|         /// Initializes a new instance of the <see cref="TestConsoleInput"/> class. |     /// Pushes the specified text to the input queue. | ||||||
|         /// </summary> |     /// </summary> | ||||||
|         public TestConsoleInput() |     /// <param name="input">The input string.</param> | ||||||
|  |     public void PushText(string input) | ||||||
|  |     { | ||||||
|  |         if (input is null) | ||||||
|         { |         { | ||||||
|             _input = new Queue<ConsoleKeyInfo>(); |             throw new ArgumentNullException(nameof(input)); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         /// <summary> |         foreach (var character in input) | ||||||
|         /// Pushes the specified text to the input queue. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="input">The input string.</param> |  | ||||||
|         public void PushText(string input) |  | ||||||
|         { |         { | ||||||
|             if (input is null) |             PushCharacter(character); | ||||||
|             { |  | ||||||
|                 throw new ArgumentNullException(nameof(input)); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             foreach (var character in input) |  | ||||||
|             { |  | ||||||
|                 PushCharacter(character); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Pushes the specified text followed by 'Enter' to the input queue. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="input">The input.</param> |  | ||||||
|         public void PushTextWithEnter(string input) |  | ||||||
|         { |  | ||||||
|             PushText(input); |  | ||||||
|             PushKey(ConsoleKey.Enter); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Pushes the specified character to the input queue. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="input">The input.</param> |  | ||||||
|         public void PushCharacter(char input) |  | ||||||
|         { |  | ||||||
|             var control = char.IsUpper(input); |  | ||||||
|             _input.Enqueue(new ConsoleKeyInfo(input, (ConsoleKey)input, false, false, control)); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Pushes the specified key to the input queue. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="input">The input.</param> |  | ||||||
|         public void PushKey(ConsoleKey input) |  | ||||||
|         { |  | ||||||
|             _input.Enqueue(new ConsoleKeyInfo((char)input, input, false, false, false)); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         public bool IsKeyAvailable() |  | ||||||
|         { |  | ||||||
|             return _input.Count > 0; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         public ConsoleKeyInfo? ReadKey(bool intercept) |  | ||||||
|         { |  | ||||||
|             if (_input.Count == 0) |  | ||||||
|             { |  | ||||||
|                 throw new InvalidOperationException("No input available."); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             return _input.Dequeue(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         public Task<ConsoleKeyInfo?> ReadKeyAsync(bool intercept, CancellationToken cancellationToken) |  | ||||||
|         { |  | ||||||
|             return Task.FromResult(ReadKey(intercept)); |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Pushes the specified text followed by 'Enter' to the input queue. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="input">The input.</param> | ||||||
|  |     public void PushTextWithEnter(string input) | ||||||
|  |     { | ||||||
|  |         PushText(input); | ||||||
|  |         PushKey(ConsoleKey.Enter); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Pushes the specified character to the input queue. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="input">The input.</param> | ||||||
|  |     public void PushCharacter(char input) | ||||||
|  |     { | ||||||
|  |         var control = char.IsUpper(input); | ||||||
|  |         _input.Enqueue(new ConsoleKeyInfo(input, (ConsoleKey)input, false, false, control)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Pushes the specified key to the input queue. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="input">The input.</param> | ||||||
|  |     public void PushKey(ConsoleKey input) | ||||||
|  |     { | ||||||
|  |         _input.Enqueue(new ConsoleKeyInfo((char)input, input, false, false, false)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <inheritdoc/> | ||||||
|  |     public bool IsKeyAvailable() | ||||||
|  |     { | ||||||
|  |         return _input.Count > 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <inheritdoc/> | ||||||
|  |     public ConsoleKeyInfo? ReadKey(bool intercept) | ||||||
|  |     { | ||||||
|  |         if (_input.Count == 0) | ||||||
|  |         { | ||||||
|  |             throw new InvalidOperationException("No input available."); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return _input.Dequeue(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <inheritdoc/> | ||||||
|  |     public Task<ConsoleKeyInfo?> ReadKeyAsync(bool intercept, CancellationToken cancellationToken) | ||||||
|  |     { | ||||||
|  |         return Task.FromResult(ReadKey(intercept)); | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,30 +1,29 @@ | |||||||
| using System; | using System; | ||||||
|  |  | ||||||
| namespace Spectre.Console | namespace Spectre.Console; | ||||||
|  |  | ||||||
|  | /// <summary> | ||||||
|  | /// A console capable of writing ANSI escape sequences. | ||||||
|  | /// </summary> | ||||||
|  | public static partial class AnsiConsole | ||||||
| { | { | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// A console capable of writing ANSI escape sequences. |     /// Writes an exception to the console. | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     public static partial class AnsiConsole |     /// <param name="exception">The exception to write to the console.</param> | ||||||
|  |     /// <param name="format">The exception format options.</param> | ||||||
|  |     public static void WriteException(Exception exception, ExceptionFormats format = ExceptionFormats.Default) | ||||||
|     { |     { | ||||||
|         /// <summary> |         Console.WriteException(exception, format); | ||||||
|         /// Writes an exception to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="exception">The exception to write to the console.</param> |  | ||||||
|         /// <param name="format">The exception format options.</param> |  | ||||||
|         public static void WriteException(Exception exception, ExceptionFormats format = ExceptionFormats.Default) |  | ||||||
|         { |  | ||||||
|             Console.WriteException(exception, format); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes an exception to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="exception">The exception to write to the console.</param> |  | ||||||
|         /// <param name="settings">The exception settings.</param> |  | ||||||
|         public static void WriteException(Exception exception, ExceptionSettings settings) |  | ||||||
|         { |  | ||||||
|             Console.WriteException(exception, settings); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes an exception to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="exception">The exception to write to the console.</param> | ||||||
|  |     /// <param name="settings">The exception settings.</param> | ||||||
|  |     public static void WriteException(Exception exception, ExceptionSettings settings) | ||||||
|  |     { | ||||||
|  |         Console.WriteException(exception, settings); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,20 +1,19 @@ | |||||||
| using Spectre.Console.Rendering; | using Spectre.Console.Rendering; | ||||||
|  |  | ||||||
| namespace Spectre.Console | namespace Spectre.Console; | ||||||
|  |  | ||||||
|  | /// <summary> | ||||||
|  | /// A console capable of writing ANSI escape sequences. | ||||||
|  | /// </summary> | ||||||
|  | public static partial class AnsiConsole | ||||||
| { | { | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// A console capable of writing ANSI escape sequences. |     /// Creates a new <see cref="LiveDisplay"/> instance. | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     public static partial class AnsiConsole |     /// <param name="target">The target renderable to update.</param> | ||||||
|  |     /// <returns>A <see cref="LiveDisplay"/> instance.</returns> | ||||||
|  |     public static LiveDisplay Live(IRenderable target) | ||||||
|     { |     { | ||||||
|         /// <summary> |         return Console.Live(target); | ||||||
|         /// Creates a new <see cref="LiveDisplay"/> instance. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="target">The target renderable to update.</param> |  | ||||||
|         /// <returns>A <see cref="LiveDisplay"/> instance.</returns> |  | ||||||
|         public static LiveDisplay Live(IRenderable target) |  | ||||||
|         { |  | ||||||
|             return Console.Live(target); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -1,70 +1,69 @@ | |||||||
| using System; | using System; | ||||||
|  |  | ||||||
| namespace Spectre.Console | namespace Spectre.Console; | ||||||
|  |  | ||||||
|  | /// <summary> | ||||||
|  | /// A console capable of writing ANSI escape sequences. | ||||||
|  | /// </summary> | ||||||
|  | public static partial class AnsiConsole | ||||||
| { | { | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// A console capable of writing ANSI escape sequences. |     /// Writes the specified markup to the console. | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     public static partial class AnsiConsole |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void Markup(string value) | ||||||
|     { |     { | ||||||
|         /// <summary> |         Console.Markup(value); | ||||||
|         /// Writes the specified markup to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         public static void Markup(string value) |  | ||||||
|         { |  | ||||||
|             Console.Markup(value); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the specified markup to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="format">A composite format string.</param> |  | ||||||
|         /// <param name="args">An array of objects to write.</param> |  | ||||||
|         public static void Markup(string format, params object[] args) |  | ||||||
|         { |  | ||||||
|             Console.Markup(format, args); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the specified markup to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="provider">An object that supplies culture-specific formatting information.</param> |  | ||||||
|         /// <param name="format">A composite format string.</param> |  | ||||||
|         /// <param name="args">An array of objects to write.</param> |  | ||||||
|         public static void Markup(IFormatProvider provider, string format, params object[] args) |  | ||||||
|         { |  | ||||||
|             Console.Markup(provider, format, args); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the specified markup, followed by the current line terminator, to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         public static void MarkupLine(string value) |  | ||||||
|         { |  | ||||||
|             Console.MarkupLine(value); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the specified markup, followed by the current line terminator, to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="format">A composite format string.</param> |  | ||||||
|         /// <param name="args">An array of objects to write.</param> |  | ||||||
|         public static void MarkupLine(string format, params object[] args) |  | ||||||
|         { |  | ||||||
|             Console.MarkupLine(format, args); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the specified markup, followed by the current line terminator, to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="provider">An object that supplies culture-specific formatting information.</param> |  | ||||||
|         /// <param name="format">A composite format string.</param> |  | ||||||
|         /// <param name="args">An array of objects to write.</param> |  | ||||||
|         public static void MarkupLine(IFormatProvider provider, string format, params object[] args) |  | ||||||
|         { |  | ||||||
|             Console.MarkupLine(provider, format, args); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the specified markup to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="format">A composite format string.</param> | ||||||
|  |     /// <param name="args">An array of objects to write.</param> | ||||||
|  |     public static void Markup(string format, params object[] args) | ||||||
|  |     { | ||||||
|  |         Console.Markup(format, args); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the specified markup to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="provider">An object that supplies culture-specific formatting information.</param> | ||||||
|  |     /// <param name="format">A composite format string.</param> | ||||||
|  |     /// <param name="args">An array of objects to write.</param> | ||||||
|  |     public static void Markup(IFormatProvider provider, string format, params object[] args) | ||||||
|  |     { | ||||||
|  |         Console.Markup(provider, format, args); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the specified markup, followed by the current line terminator, to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void MarkupLine(string value) | ||||||
|  |     { | ||||||
|  |         Console.MarkupLine(value); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the specified markup, followed by the current line terminator, to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="format">A composite format string.</param> | ||||||
|  |     /// <param name="args">An array of objects to write.</param> | ||||||
|  |     public static void MarkupLine(string format, params object[] args) | ||||||
|  |     { | ||||||
|  |         Console.MarkupLine(format, args); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the specified markup, followed by the current line terminator, to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="provider">An object that supplies culture-specific formatting information.</param> | ||||||
|  |     /// <param name="format">A composite format string.</param> | ||||||
|  |     /// <param name="args">An array of objects to write.</param> | ||||||
|  |     public static void MarkupLine(IFormatProvider provider, string format, params object[] args) | ||||||
|  |     { | ||||||
|  |         Console.MarkupLine(provider, format, args); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,26 +1,25 @@ | |||||||
| namespace Spectre.Console | namespace Spectre.Console; | ||||||
|  |  | ||||||
|  | /// <summary> | ||||||
|  | /// A console capable of writing ANSI escape sequences. | ||||||
|  | /// </summary> | ||||||
|  | public static partial class AnsiConsole | ||||||
| { | { | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// A console capable of writing ANSI escape sequences. |     /// Creates a new <see cref="Progress"/> instance. | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     public static partial class AnsiConsole |     /// <returns>A <see cref="Progress"/> instance.</returns> | ||||||
|  |     public static Progress Progress() | ||||||
|     { |     { | ||||||
|         /// <summary> |         return Console.Progress(); | ||||||
|         /// Creates a new <see cref="Progress"/> instance. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <returns>A <see cref="Progress"/> instance.</returns> |  | ||||||
|         public static Progress Progress() |  | ||||||
|         { |  | ||||||
|             return Console.Progress(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Creates a new <see cref="Status"/> instance. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <returns>A <see cref="Status"/> instance.</returns> |  | ||||||
|         public static Status Status() |  | ||||||
|         { |  | ||||||
|             return Console.Status(); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Creates a new <see cref="Status"/> instance. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <returns>A <see cref="Status"/> instance.</returns> | ||||||
|  |     public static Status Status() | ||||||
|  |     { | ||||||
|  |         return Console.Status(); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,66 +1,65 @@ | |||||||
| using System; | using System; | ||||||
|  |  | ||||||
| namespace Spectre.Console | namespace Spectre.Console; | ||||||
|  |  | ||||||
|  | /// <summary> | ||||||
|  | /// A console capable of writing ANSI escape sequences. | ||||||
|  | /// </summary> | ||||||
|  | public static partial class AnsiConsole | ||||||
| { | { | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// A console capable of writing ANSI escape sequences. |     /// Displays a prompt to the user. | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     public static partial class AnsiConsole |     /// <typeparam name="T">The prompt result type.</typeparam> | ||||||
|  |     /// <param name="prompt">The prompt to display.</param> | ||||||
|  |     /// <returns>The prompt input result.</returns> | ||||||
|  |     public static T Prompt<T>(IPrompt<T> prompt) | ||||||
|     { |     { | ||||||
|         /// <summary> |         if (prompt is null) | ||||||
|         /// Displays a prompt to the user. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <typeparam name="T">The prompt result type.</typeparam> |  | ||||||
|         /// <param name="prompt">The prompt to display.</param> |  | ||||||
|         /// <returns>The prompt input result.</returns> |  | ||||||
|         public static T Prompt<T>(IPrompt<T> prompt) |  | ||||||
|         { |         { | ||||||
|             if (prompt is null) |             throw new ArgumentNullException(nameof(prompt)); | ||||||
|             { |  | ||||||
|                 throw new ArgumentNullException(nameof(prompt)); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             return prompt.Show(Console); |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         /// <summary> |         return prompt.Show(Console); | ||||||
|         /// Displays a prompt to the user. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <typeparam name="T">The prompt result type.</typeparam> |  | ||||||
|         /// <param name="prompt">The prompt markup text.</param> |  | ||||||
|         /// <returns>The prompt input result.</returns> |  | ||||||
|         public static T Ask<T>(string prompt) |  | ||||||
|         { |  | ||||||
|             return new TextPrompt<T>(prompt).Show(Console); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Displays a prompt to the user with a given default. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <typeparam name="T">The prompt result type.</typeparam> |  | ||||||
|         /// <param name="prompt">The prompt markup text.</param> |  | ||||||
|         /// <param name="defaultValue">The default value.</param> |  | ||||||
|         /// <returns>The prompt input result.</returns> |  | ||||||
|         public static T Ask<T>(string prompt, T defaultValue) |  | ||||||
|         { |  | ||||||
|             return new TextPrompt<T>(prompt) |  | ||||||
|                 .DefaultValue(defaultValue) |  | ||||||
|                 .Show(Console); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Displays a prompt with two choices, yes or no. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="prompt">The prompt markup text.</param> |  | ||||||
|         /// <param name="defaultValue">Specifies the default answer.</param> |  | ||||||
|         /// <returns><c>true</c> if the user selected "yes", otherwise <c>false</c>.</returns> |  | ||||||
|         public static bool Confirm(string prompt, bool defaultValue = true) |  | ||||||
|         { |  | ||||||
|             return new ConfirmationPrompt(prompt) |  | ||||||
|             { |  | ||||||
|                 DefaultValue = defaultValue, |  | ||||||
|             } |  | ||||||
|             .Show(Console); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Displays a prompt to the user. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <typeparam name="T">The prompt result type.</typeparam> | ||||||
|  |     /// <param name="prompt">The prompt markup text.</param> | ||||||
|  |     /// <returns>The prompt input result.</returns> | ||||||
|  |     public static T Ask<T>(string prompt) | ||||||
|  |     { | ||||||
|  |         return new TextPrompt<T>(prompt).Show(Console); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Displays a prompt to the user with a given default. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <typeparam name="T">The prompt result type.</typeparam> | ||||||
|  |     /// <param name="prompt">The prompt markup text.</param> | ||||||
|  |     /// <param name="defaultValue">The default value.</param> | ||||||
|  |     /// <returns>The prompt input result.</returns> | ||||||
|  |     public static T Ask<T>(string prompt, T defaultValue) | ||||||
|  |     { | ||||||
|  |         return new TextPrompt<T>(prompt) | ||||||
|  |             .DefaultValue(defaultValue) | ||||||
|  |             .Show(Console); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Displays a prompt with two choices, yes or no. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="prompt">The prompt markup text.</param> | ||||||
|  |     /// <param name="defaultValue">Specifies the default answer.</param> | ||||||
|  |     /// <returns><c>true</c> if the user selected "yes", otherwise <c>false</c>.</returns> | ||||||
|  |     public static bool Confirm(string prompt, bool defaultValue = true) | ||||||
|  |     { | ||||||
|  |         return new ConfirmationPrompt(prompt) | ||||||
|  |         { | ||||||
|  |             DefaultValue = defaultValue, | ||||||
|  |         } | ||||||
|  |         .Show(Console); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,70 +1,69 @@ | |||||||
| using System; | using System; | ||||||
| using Spectre.Console.Rendering; | using Spectre.Console.Rendering; | ||||||
|  |  | ||||||
| namespace Spectre.Console | namespace Spectre.Console; | ||||||
|  |  | ||||||
|  | /// <summary> | ||||||
|  | /// A console capable of writing ANSI escape sequences. | ||||||
|  | /// </summary> | ||||||
|  | public static partial class AnsiConsole | ||||||
| { | { | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// A console capable of writing ANSI escape sequences. |     /// Starts recording the console output. | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     public static partial class AnsiConsole |     public static void Record() | ||||||
|     { |     { | ||||||
|         /// <summary> |         if (_recorder == null) | ||||||
|         /// Starts recording the console output. |  | ||||||
|         /// </summary> |  | ||||||
|         public static void Record() |  | ||||||
|         { |         { | ||||||
|             if (_recorder == null) |             _recorder = new Recorder(Console); | ||||||
|             { |  | ||||||
|                 _recorder = new Recorder(Console); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Exports all recorded console output as text. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <returns>The recorded output as text.</returns> |  | ||||||
|         public static string ExportText() |  | ||||||
|         { |  | ||||||
|             if (_recorder == null) |  | ||||||
|             { |  | ||||||
|                 throw new InvalidOperationException("Cannot export text since a recording hasn't been started."); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             return _recorder.ExportText(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Exports all recorded console output as HTML text. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <returns>The recorded output as HTML text.</returns> |  | ||||||
|         public static string ExportHtml() |  | ||||||
|         { |  | ||||||
|             if (_recorder == null) |  | ||||||
|             { |  | ||||||
|                 throw new InvalidOperationException("Cannot export HTML since a recording hasn't been started."); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             return _recorder.ExportHtml(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Exports all recorded console output using a custom encoder. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="encoder">The encoder to use.</param> |  | ||||||
|         /// <returns>The recorded output.</returns> |  | ||||||
|         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); |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Exports all recorded console output as text. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <returns>The recorded output as text.</returns> | ||||||
|  |     public static string ExportText() | ||||||
|  |     { | ||||||
|  |         if (_recorder == null) | ||||||
|  |         { | ||||||
|  |             throw new InvalidOperationException("Cannot export text since a recording hasn't been started."); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return _recorder.ExportText(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Exports all recorded console output as HTML text. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <returns>The recorded output as HTML text.</returns> | ||||||
|  |     public static string ExportHtml() | ||||||
|  |     { | ||||||
|  |         if (_recorder == null) | ||||||
|  |         { | ||||||
|  |             throw new InvalidOperationException("Cannot export HTML since a recording hasn't been started."); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return _recorder.ExportHtml(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Exports all recorded console output using a custom encoder. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="encoder">The encoder to use.</param> | ||||||
|  |     /// <returns>The recorded output.</returns> | ||||||
|  |     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); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,35 +1,34 @@ | |||||||
| using System; | using System; | ||||||
| using Spectre.Console.Rendering; | using Spectre.Console.Rendering; | ||||||
|  |  | ||||||
| namespace Spectre.Console | namespace Spectre.Console; | ||||||
|  |  | ||||||
|  | /// <summary> | ||||||
|  | /// A console capable of writing ANSI escape sequences. | ||||||
|  | /// </summary> | ||||||
|  | public static partial class AnsiConsole | ||||||
| { | { | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// A console capable of writing ANSI escape sequences. |     /// Renders the specified object to the console. | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     public static partial class AnsiConsole |     /// <param name="renderable">The object to render.</param> | ||||||
|  |     [Obsolete("Consider using AnsiConsole.Write instead.")] | ||||||
|  |     public static void Render(IRenderable renderable) | ||||||
|     { |     { | ||||||
|         /// <summary> |         Write(renderable); | ||||||
|         /// Renders the specified object to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="renderable">The object to render.</param> |  | ||||||
|         [Obsolete("Consider using AnsiConsole.Write instead.")] |  | ||||||
|         public static void Render(IRenderable renderable) |  | ||||||
|         { |  | ||||||
|             Write(renderable); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Renders the specified <see cref="IRenderable"/> to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="renderable">The object to render.</param> |  | ||||||
|         public static void Write(IRenderable renderable) |  | ||||||
|         { |  | ||||||
|             if (renderable is null) |  | ||||||
|             { |  | ||||||
|                 throw new ArgumentNullException(nameof(renderable)); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             Console.Write(renderable); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Renders the specified <see cref="IRenderable"/> to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="renderable">The object to render.</param> | ||||||
|  |     public static void Write(IRenderable renderable) | ||||||
|  |     { | ||||||
|  |         if (renderable is null) | ||||||
|  |         { | ||||||
|  |             throw new ArgumentNullException(nameof(renderable)); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         Console.Write(renderable); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,19 +1,18 @@ | |||||||
| using System; | using System; | ||||||
|  |  | ||||||
| namespace Spectre.Console | namespace Spectre.Console; | ||||||
|  |  | ||||||
|  | /// <summary> | ||||||
|  | /// A console capable of writing ANSI escape sequences. | ||||||
|  | /// </summary> | ||||||
|  | public static partial class AnsiConsole | ||||||
| { | { | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// A console capable of writing ANSI escape sequences. |     /// Switches to an alternate screen buffer if the terminal supports it. | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     public static partial class AnsiConsole |     /// <param name="action">The action to execute within the alternate screen buffer.</param> | ||||||
|  |     public static void AlternateScreen(Action action) | ||||||
|     { |     { | ||||||
|         /// <summary> |         Console.AlternateScreen(action); | ||||||
|         /// Switches to an alternate screen buffer if the terminal supports it. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="action">The action to execute within the alternate screen buffer.</param> |  | ||||||
|         public static void AlternateScreen(Action action) |  | ||||||
|         { |  | ||||||
|             Console.AlternateScreen(action); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -1,63 +1,62 @@ | |||||||
| namespace Spectre.Console | namespace Spectre.Console; | ||||||
|  |  | ||||||
|  | /// <summary> | ||||||
|  | /// A console capable of writing ANSI escape sequences. | ||||||
|  | /// </summary> | ||||||
|  | public static partial class AnsiConsole | ||||||
| { | { | ||||||
|  |     internal static Style CurrentStyle { get; private set; } = Style.Plain; | ||||||
|  |     internal static bool Created { get; private set; } | ||||||
|  |  | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// A console capable of writing ANSI escape sequences. |     /// Gets or sets the foreground color. | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     public static partial class AnsiConsole |     public static Color Foreground | ||||||
|     { |     { | ||||||
|         internal static Style CurrentStyle { get; private set; } = Style.Plain; |         get => CurrentStyle.Foreground; | ||||||
|         internal static bool Created { get; private set; } |         set => CurrentStyle = CurrentStyle.Foreground(value); | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Gets or sets the foreground color. |  | ||||||
|         /// </summary> |  | ||||||
|         public static Color Foreground |  | ||||||
|         { |  | ||||||
|             get => CurrentStyle.Foreground; |  | ||||||
|             set => CurrentStyle = CurrentStyle.Foreground(value); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Gets or sets the background color. |  | ||||||
|         /// </summary> |  | ||||||
|         public static Color Background |  | ||||||
|         { |  | ||||||
|             get => CurrentStyle.Background; |  | ||||||
|             set => CurrentStyle = CurrentStyle.Background(value); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Gets or sets the text decoration. |  | ||||||
|         /// </summary> |  | ||||||
|         public static Decoration Decoration |  | ||||||
|         { |  | ||||||
|             get => CurrentStyle.Decoration; |  | ||||||
|             set => CurrentStyle = CurrentStyle.Decoration(value); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Resets colors and text decorations. |  | ||||||
|         /// </summary> |  | ||||||
|         public static void Reset() |  | ||||||
|         { |  | ||||||
|             ResetColors(); |  | ||||||
|             ResetDecoration(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Resets the current applied text decorations. |  | ||||||
|         /// </summary> |  | ||||||
|         public static void ResetDecoration() |  | ||||||
|         { |  | ||||||
|             Decoration = Decoration.None; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Resets the current applied foreground and background colors. |  | ||||||
|         /// </summary> |  | ||||||
|         public static void ResetColors() |  | ||||||
|         { |  | ||||||
|             CurrentStyle = Style.Plain; |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Gets or sets the background color. | ||||||
|  |     /// </summary> | ||||||
|  |     public static Color Background | ||||||
|  |     { | ||||||
|  |         get => CurrentStyle.Background; | ||||||
|  |         set => CurrentStyle = CurrentStyle.Background(value); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Gets or sets the text decoration. | ||||||
|  |     /// </summary> | ||||||
|  |     public static Decoration Decoration | ||||||
|  |     { | ||||||
|  |         get => CurrentStyle.Decoration; | ||||||
|  |         set => CurrentStyle = CurrentStyle.Decoration(value); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Resets colors and text decorations. | ||||||
|  |     /// </summary> | ||||||
|  |     public static void Reset() | ||||||
|  |     { | ||||||
|  |         ResetColors(); | ||||||
|  |         ResetDecoration(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Resets the current applied text decorations. | ||||||
|  |     /// </summary> | ||||||
|  |     public static void ResetDecoration() | ||||||
|  |     { | ||||||
|  |         Decoration = Decoration.None; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Resets the current applied foreground and background colors. | ||||||
|  |     /// </summary> | ||||||
|  |     public static void ResetColors() | ||||||
|  |     { | ||||||
|  |         CurrentStyle = Style.Plain; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,253 +1,252 @@ | |||||||
| using System; | using System; | ||||||
| using System.Globalization; | using System.Globalization; | ||||||
|  |  | ||||||
| namespace Spectre.Console | namespace Spectre.Console; | ||||||
|  |  | ||||||
|  | /// <summary> | ||||||
|  | /// A console capable of writing ANSI escape sequences. | ||||||
|  | /// </summary> | ||||||
|  | public static partial class AnsiConsole | ||||||
| { | { | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// A console capable of writing ANSI escape sequences. |     /// Writes the specified string value to the console. | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     public static partial class AnsiConsole |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void Write(string value) | ||||||
|     { |     { | ||||||
|         /// <summary> |         Write(value, CurrentStyle); | ||||||
|         /// Writes the specified string value to the console. |     } | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="value">The value to write.</param> |     /// <summary> | ||||||
|         public static void Write(string value) |     /// Writes the text representation of the specified 32-bit | ||||||
|  |     /// signed integer value to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void Write(int value) | ||||||
|  |     { | ||||||
|  |         Write(CultureInfo.CurrentCulture, value); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the text representation of the specified 32-bit | ||||||
|  |     /// signed integer value to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="provider">An object that supplies culture-specific formatting information.</param> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void Write(IFormatProvider provider, int value) | ||||||
|  |     { | ||||||
|  |         Console.Write(value.ToString(provider), CurrentStyle); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the text representation of the specified 32-bit | ||||||
|  |     /// unsigned integer value to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void Write(uint value) | ||||||
|  |     { | ||||||
|  |         Write(CultureInfo.CurrentCulture, value); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the text representation of the specified 32-bit | ||||||
|  |     /// unsigned integer value to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="provider">An object that supplies culture-specific formatting information.</param> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void Write(IFormatProvider provider, uint value) | ||||||
|  |     { | ||||||
|  |         Console.Write(value.ToString(provider), CurrentStyle); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the text representation of the specified 64-bit | ||||||
|  |     /// signed integer value to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void Write(long value) | ||||||
|  |     { | ||||||
|  |         Write(CultureInfo.CurrentCulture, value); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the text representation of the specified 64-bit | ||||||
|  |     /// signed integer value to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="provider">An object that supplies culture-specific formatting information.</param> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void Write(IFormatProvider provider, long value) | ||||||
|  |     { | ||||||
|  |         Console.Write(value.ToString(provider), CurrentStyle); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the text representation of the specified 64-bit | ||||||
|  |     /// unsigned integer value to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void Write(ulong value) | ||||||
|  |     { | ||||||
|  |         Write(CultureInfo.CurrentCulture, value); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the text representation of the specified 64-bit | ||||||
|  |     /// unsigned integer value to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="provider">An object that supplies culture-specific formatting information.</param> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void Write(IFormatProvider provider, ulong value) | ||||||
|  |     { | ||||||
|  |         Console.Write(value.ToString(provider), CurrentStyle); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the text representation of the specified single-precision | ||||||
|  |     /// floating-point value to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void Write(float value) | ||||||
|  |     { | ||||||
|  |         Write(CultureInfo.CurrentCulture, value); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the text representation of the specified single-precision | ||||||
|  |     /// floating-point value to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="provider">An object that supplies culture-specific formatting information.</param> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void Write(IFormatProvider provider, float value) | ||||||
|  |     { | ||||||
|  |         Console.Write(value.ToString(provider), CurrentStyle); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the text representation of the specified double-precision | ||||||
|  |     /// floating-point value to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void Write(double value) | ||||||
|  |     { | ||||||
|  |         Write(CultureInfo.CurrentCulture, value); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the text representation of the specified double-precision | ||||||
|  |     /// floating-point value to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="provider">An object that supplies culture-specific formatting information.</param> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void Write(IFormatProvider provider, double value) | ||||||
|  |     { | ||||||
|  |         Console.Write(value.ToString(provider), CurrentStyle); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the text representation of the specified decimal value, to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void Write(decimal value) | ||||||
|  |     { | ||||||
|  |         Write(CultureInfo.CurrentCulture, value); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the text representation of the specified decimal value, to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="provider">An object that supplies culture-specific formatting information.</param> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void Write(IFormatProvider provider, decimal value) | ||||||
|  |     { | ||||||
|  |         Console.Write(value.ToString(provider), CurrentStyle); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the text representation of the specified boolean value to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void Write(bool value) | ||||||
|  |     { | ||||||
|  |         Write(CultureInfo.CurrentCulture, value); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the text representation of the specified boolean value to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="provider">An object that supplies culture-specific formatting information.</param> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void Write(IFormatProvider provider, bool value) | ||||||
|  |     { | ||||||
|  |         Console.Write(value.ToString(provider), CurrentStyle); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the specified Unicode character to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void Write(char value) | ||||||
|  |     { | ||||||
|  |         Write(CultureInfo.CurrentCulture, value); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the specified Unicode character to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="provider">An object that supplies culture-specific formatting information.</param> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void Write(IFormatProvider provider, char value) | ||||||
|  |     { | ||||||
|  |         Console.Write(value.ToString(provider), CurrentStyle); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the specified array of Unicode characters to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void Write(char[] value) | ||||||
|  |     { | ||||||
|  |         Write(CultureInfo.CurrentCulture, value); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the specified array of Unicode characters to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="provider">An object that supplies culture-specific formatting information.</param> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void Write(IFormatProvider provider, char[] value) | ||||||
|  |     { | ||||||
|  |         if (value is null) | ||||||
|         { |         { | ||||||
|             Write(value, CurrentStyle); |             throw new ArgumentNullException(nameof(value)); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         /// <summary> |         for (var index = 0; index < value.Length; index++) | ||||||
|         /// Writes the text representation of the specified 32-bit |  | ||||||
|         /// signed integer value to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         public static void Write(int value) |  | ||||||
|         { |         { | ||||||
|             Write(CultureInfo.CurrentCulture, value); |             Console.Write(value[index].ToString(provider), CurrentStyle); | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the text representation of the specified 32-bit |  | ||||||
|         /// signed integer value to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="provider">An object that supplies culture-specific formatting information.</param> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         public static void Write(IFormatProvider provider, int value) |  | ||||||
|         { |  | ||||||
|             Console.Write(value.ToString(provider), CurrentStyle); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the text representation of the specified 32-bit |  | ||||||
|         /// unsigned integer value to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         public static void Write(uint value) |  | ||||||
|         { |  | ||||||
|             Write(CultureInfo.CurrentCulture, value); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the text representation of the specified 32-bit |  | ||||||
|         /// unsigned integer value to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="provider">An object that supplies culture-specific formatting information.</param> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         public static void Write(IFormatProvider provider, uint value) |  | ||||||
|         { |  | ||||||
|             Console.Write(value.ToString(provider), CurrentStyle); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the text representation of the specified 64-bit |  | ||||||
|         /// signed integer value to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         public static void Write(long value) |  | ||||||
|         { |  | ||||||
|             Write(CultureInfo.CurrentCulture, value); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the text representation of the specified 64-bit |  | ||||||
|         /// signed integer value to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="provider">An object that supplies culture-specific formatting information.</param> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         public static void Write(IFormatProvider provider, long value) |  | ||||||
|         { |  | ||||||
|             Console.Write(value.ToString(provider), CurrentStyle); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the text representation of the specified 64-bit |  | ||||||
|         /// unsigned integer value to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         public static void Write(ulong value) |  | ||||||
|         { |  | ||||||
|             Write(CultureInfo.CurrentCulture, value); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the text representation of the specified 64-bit |  | ||||||
|         /// unsigned integer value to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="provider">An object that supplies culture-specific formatting information.</param> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         public static void Write(IFormatProvider provider, ulong value) |  | ||||||
|         { |  | ||||||
|             Console.Write(value.ToString(provider), CurrentStyle); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the text representation of the specified single-precision |  | ||||||
|         /// floating-point value to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         public static void Write(float value) |  | ||||||
|         { |  | ||||||
|             Write(CultureInfo.CurrentCulture, value); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the text representation of the specified single-precision |  | ||||||
|         /// floating-point value to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="provider">An object that supplies culture-specific formatting information.</param> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         public static void Write(IFormatProvider provider, float value) |  | ||||||
|         { |  | ||||||
|             Console.Write(value.ToString(provider), CurrentStyle); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the text representation of the specified double-precision |  | ||||||
|         /// floating-point value to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         public static void Write(double value) |  | ||||||
|         { |  | ||||||
|             Write(CultureInfo.CurrentCulture, value); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the text representation of the specified double-precision |  | ||||||
|         /// floating-point value to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="provider">An object that supplies culture-specific formatting information.</param> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         public static void Write(IFormatProvider provider, double value) |  | ||||||
|         { |  | ||||||
|             Console.Write(value.ToString(provider), CurrentStyle); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the text representation of the specified decimal value, to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         public static void Write(decimal value) |  | ||||||
|         { |  | ||||||
|             Write(CultureInfo.CurrentCulture, value); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the text representation of the specified decimal value, to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="provider">An object that supplies culture-specific formatting information.</param> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         public static void Write(IFormatProvider provider, decimal value) |  | ||||||
|         { |  | ||||||
|             Console.Write(value.ToString(provider), CurrentStyle); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the text representation of the specified boolean value to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         public static void Write(bool value) |  | ||||||
|         { |  | ||||||
|             Write(CultureInfo.CurrentCulture, value); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the text representation of the specified boolean value to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="provider">An object that supplies culture-specific formatting information.</param> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         public static void Write(IFormatProvider provider, bool value) |  | ||||||
|         { |  | ||||||
|             Console.Write(value.ToString(provider), CurrentStyle); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the specified Unicode character to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         public static void Write(char value) |  | ||||||
|         { |  | ||||||
|             Write(CultureInfo.CurrentCulture, value); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the specified Unicode character to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="provider">An object that supplies culture-specific formatting information.</param> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         public static void Write(IFormatProvider provider, char value) |  | ||||||
|         { |  | ||||||
|             Console.Write(value.ToString(provider), CurrentStyle); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the specified array of Unicode characters to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         public static void Write(char[] value) |  | ||||||
|         { |  | ||||||
|             Write(CultureInfo.CurrentCulture, value); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the specified array of Unicode characters to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="provider">An object that supplies culture-specific formatting information.</param> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         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); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the text representation of the specified array of objects, |  | ||||||
|         /// to the console using the specified format information. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="format">A composite format string.</param> |  | ||||||
|         /// <param name="args">An array of objects to write.</param> |  | ||||||
|         public static void Write(string format, params object[] args) |  | ||||||
|         { |  | ||||||
|             Write(CultureInfo.CurrentCulture, format, args); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the text representation of the specified array of objects, |  | ||||||
|         /// to the console using the specified format information. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="provider">An object that supplies culture-specific formatting information.</param> |  | ||||||
|         /// <param name="format">A composite format string.</param> |  | ||||||
|         /// <param name="args">An array of objects to write.</param> |  | ||||||
|         public static void Write(IFormatProvider provider, string format, params object[] args) |  | ||||||
|         { |  | ||||||
|             Console.Write(string.Format(provider, format, args), CurrentStyle); |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the text representation of the specified array of objects, | ||||||
|  |     /// to the console using the specified format information. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="format">A composite format string.</param> | ||||||
|  |     /// <param name="args">An array of objects to write.</param> | ||||||
|  |     public static void Write(string format, params object[] args) | ||||||
|  |     { | ||||||
|  |         Write(CultureInfo.CurrentCulture, format, args); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the text representation of the specified array of objects, | ||||||
|  |     /// to the console using the specified format information. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="provider">An object that supplies culture-specific formatting information.</param> | ||||||
|  |     /// <param name="format">A composite format string.</param> | ||||||
|  |     /// <param name="args">An array of objects to write.</param> | ||||||
|  |     public static void Write(IFormatProvider provider, string format, params object[] args) | ||||||
|  |     { | ||||||
|  |         Console.Write(string.Format(provider, format, args), CurrentStyle); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,273 +1,272 @@ | |||||||
| using System; | using System; | ||||||
| using System.Globalization; | using System.Globalization; | ||||||
|  |  | ||||||
| namespace Spectre.Console | namespace Spectre.Console; | ||||||
|  |  | ||||||
|  | /// <summary> | ||||||
|  | /// A console capable of writing ANSI escape sequences. | ||||||
|  | /// </summary> | ||||||
|  | public static partial class AnsiConsole | ||||||
| { | { | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// A console capable of writing ANSI escape sequences. |     /// Writes an empty line to the console. | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     public static partial class AnsiConsole |     public static void WriteLine() | ||||||
|     { |     { | ||||||
|         /// <summary> |         Console.WriteLine(); | ||||||
|         /// Writes an empty line to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         public static void WriteLine() |  | ||||||
|         { |  | ||||||
|             Console.WriteLine(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the specified string value, followed by the current line terminator, to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         public static void WriteLine(string value) |  | ||||||
|         { |  | ||||||
|             Console.WriteLine(value, CurrentStyle); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the text representation of the specified 32-bit signed integer value, |  | ||||||
|         /// followed by the current line terminator, to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         public static void WriteLine(int value) |  | ||||||
|         { |  | ||||||
|             WriteLine(CultureInfo.CurrentCulture, value); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the text representation of the specified 32-bit signed integer value, |  | ||||||
|         /// followed by the current line terminator, to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="provider">An object that supplies culture-specific formatting information.</param> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         public static void WriteLine(IFormatProvider provider, int value) |  | ||||||
|         { |  | ||||||
|             Console.WriteLine(value.ToString(provider), CurrentStyle); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the text representation of the specified 32-bit unsigned integer value, |  | ||||||
|         /// followed by the current line terminator, to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         public static void WriteLine(uint value) |  | ||||||
|         { |  | ||||||
|             WriteLine(CultureInfo.CurrentCulture, value); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the text representation of the specified 32-bit unsigned integer value, |  | ||||||
|         /// followed by the current line terminator, to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="provider">An object that supplies culture-specific formatting information.</param> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         public static void WriteLine(IFormatProvider provider, uint value) |  | ||||||
|         { |  | ||||||
|             Console.WriteLine(value.ToString(provider), CurrentStyle); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the text representation of the specified 64-bit signed integer value, |  | ||||||
|         /// followed by the current line terminator, to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         public static void WriteLine(long value) |  | ||||||
|         { |  | ||||||
|             WriteLine(CultureInfo.CurrentCulture, value); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the text representation of the specified 64-bit signed integer value, |  | ||||||
|         /// followed by the current line terminator, to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="provider">An object that supplies culture-specific formatting information.</param> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         public static void WriteLine(IFormatProvider provider, long value) |  | ||||||
|         { |  | ||||||
|             Console.WriteLine(value.ToString(provider), CurrentStyle); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the text representation of the specified 64-bit unsigned integer value, |  | ||||||
|         /// followed by the current line terminator, to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         public static void WriteLine(ulong value) |  | ||||||
|         { |  | ||||||
|             WriteLine(CultureInfo.CurrentCulture, value); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the text representation of the specified 64-bit unsigned integer value, |  | ||||||
|         /// followed by the current line terminator, to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="provider">An object that supplies culture-specific formatting information.</param> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         public static void WriteLine(IFormatProvider provider, ulong value) |  | ||||||
|         { |  | ||||||
|             Console.WriteLine(value.ToString(provider), CurrentStyle); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the text representation of the specified single-precision floating-point |  | ||||||
|         /// value, followed by the current line terminator, to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         public static void WriteLine(float value) |  | ||||||
|         { |  | ||||||
|             WriteLine(CultureInfo.CurrentCulture, value); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the text representation of the specified single-precision floating-point |  | ||||||
|         /// value, followed by the current line terminator, to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="provider">An object that supplies culture-specific formatting information.</param> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         public static void WriteLine(IFormatProvider provider, float value) |  | ||||||
|         { |  | ||||||
|             Console.WriteLine(value.ToString(provider), CurrentStyle); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the text representation of the specified double-precision floating-point |  | ||||||
|         /// value, followed by the current line terminator, to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         public static void WriteLine(double value) |  | ||||||
|         { |  | ||||||
|             WriteLine(CultureInfo.CurrentCulture, value); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the text representation of the specified double-precision floating-point |  | ||||||
|         /// value, followed by the current line terminator, to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="provider">An object that supplies culture-specific formatting information.</param> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         public static void WriteLine(IFormatProvider provider, double value) |  | ||||||
|         { |  | ||||||
|             Console.WriteLine(value.ToString(provider), CurrentStyle); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the text representation of the specified decimal value, |  | ||||||
|         /// followed by the current line terminator, to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         public static void WriteLine(decimal value) |  | ||||||
|         { |  | ||||||
|             WriteLine(CultureInfo.CurrentCulture, value); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the text representation of the specified decimal value, |  | ||||||
|         /// followed by the current line terminator, to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="provider">An object that supplies culture-specific formatting information.</param> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         public static void WriteLine(IFormatProvider provider, decimal value) |  | ||||||
|         { |  | ||||||
|             Console.WriteLine(value.ToString(provider), CurrentStyle); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the text representation of the specified boolean value, |  | ||||||
|         /// followed by the current line terminator, to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         public static void WriteLine(bool value) |  | ||||||
|         { |  | ||||||
|             WriteLine(CultureInfo.CurrentCulture, value); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the text representation of the specified boolean value, |  | ||||||
|         /// followed by the current line terminator, to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="provider">An object that supplies culture-specific formatting information.</param> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         public static void WriteLine(IFormatProvider provider, bool value) |  | ||||||
|         { |  | ||||||
|             Console.WriteLine(value.ToString(provider), CurrentStyle); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the specified Unicode character, followed by the current |  | ||||||
|         /// line terminator, value to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         public static void WriteLine(char value) |  | ||||||
|         { |  | ||||||
|             WriteLine(CultureInfo.CurrentCulture, value); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the specified Unicode character, followed by the current |  | ||||||
|         /// line terminator, value to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="provider">An object that supplies culture-specific formatting information.</param> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         public static void WriteLine(IFormatProvider provider, char value) |  | ||||||
|         { |  | ||||||
|             Console.WriteLine(value.ToString(provider), CurrentStyle); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the specified array of Unicode characters, followed by the current |  | ||||||
|         /// line terminator, value to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         public static void WriteLine(char[] value) |  | ||||||
|         { |  | ||||||
|             WriteLine(CultureInfo.CurrentCulture, value); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the specified array of Unicode characters, followed by the current |  | ||||||
|         /// line terminator, value to the console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="provider">An object that supplies culture-specific formatting information.</param> |  | ||||||
|         /// <param name="value">The value to write.</param> |  | ||||||
|         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(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the text representation of the specified array of objects, |  | ||||||
|         /// followed by the current line terminator, to the console |  | ||||||
|         /// using the specified format information. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="format">A composite format string.</param> |  | ||||||
|         /// <param name="args">An array of objects to write.</param> |  | ||||||
|         public static void WriteLine(string format, params object[] args) |  | ||||||
|         { |  | ||||||
|             WriteLine(CultureInfo.CurrentCulture, format, args); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Writes the text representation of the specified array of objects, |  | ||||||
|         /// followed by the current line terminator, to the console |  | ||||||
|         /// using the specified format information. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="provider">An object that supplies culture-specific formatting information.</param> |  | ||||||
|         /// <param name="format">A composite format string.</param> |  | ||||||
|         /// <param name="args">An array of objects to write.</param> |  | ||||||
|         public static void WriteLine(IFormatProvider provider, string format, params object[] args) |  | ||||||
|         { |  | ||||||
|             Console.WriteLine(string.Format(provider, format, args), CurrentStyle); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the specified string value, followed by the current line terminator, to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void WriteLine(string value) | ||||||
|  |     { | ||||||
|  |         Console.WriteLine(value, CurrentStyle); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the text representation of the specified 32-bit signed integer value, | ||||||
|  |     /// followed by the current line terminator, to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void WriteLine(int value) | ||||||
|  |     { | ||||||
|  |         WriteLine(CultureInfo.CurrentCulture, value); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the text representation of the specified 32-bit signed integer value, | ||||||
|  |     /// followed by the current line terminator, to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="provider">An object that supplies culture-specific formatting information.</param> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void WriteLine(IFormatProvider provider, int value) | ||||||
|  |     { | ||||||
|  |         Console.WriteLine(value.ToString(provider), CurrentStyle); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the text representation of the specified 32-bit unsigned integer value, | ||||||
|  |     /// followed by the current line terminator, to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void WriteLine(uint value) | ||||||
|  |     { | ||||||
|  |         WriteLine(CultureInfo.CurrentCulture, value); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the text representation of the specified 32-bit unsigned integer value, | ||||||
|  |     /// followed by the current line terminator, to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="provider">An object that supplies culture-specific formatting information.</param> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void WriteLine(IFormatProvider provider, uint value) | ||||||
|  |     { | ||||||
|  |         Console.WriteLine(value.ToString(provider), CurrentStyle); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the text representation of the specified 64-bit signed integer value, | ||||||
|  |     /// followed by the current line terminator, to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void WriteLine(long value) | ||||||
|  |     { | ||||||
|  |         WriteLine(CultureInfo.CurrentCulture, value); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the text representation of the specified 64-bit signed integer value, | ||||||
|  |     /// followed by the current line terminator, to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="provider">An object that supplies culture-specific formatting information.</param> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void WriteLine(IFormatProvider provider, long value) | ||||||
|  |     { | ||||||
|  |         Console.WriteLine(value.ToString(provider), CurrentStyle); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the text representation of the specified 64-bit unsigned integer value, | ||||||
|  |     /// followed by the current line terminator, to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void WriteLine(ulong value) | ||||||
|  |     { | ||||||
|  |         WriteLine(CultureInfo.CurrentCulture, value); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the text representation of the specified 64-bit unsigned integer value, | ||||||
|  |     /// followed by the current line terminator, to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="provider">An object that supplies culture-specific formatting information.</param> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void WriteLine(IFormatProvider provider, ulong value) | ||||||
|  |     { | ||||||
|  |         Console.WriteLine(value.ToString(provider), CurrentStyle); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the text representation of the specified single-precision floating-point | ||||||
|  |     /// value, followed by the current line terminator, to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void WriteLine(float value) | ||||||
|  |     { | ||||||
|  |         WriteLine(CultureInfo.CurrentCulture, value); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the text representation of the specified single-precision floating-point | ||||||
|  |     /// value, followed by the current line terminator, to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="provider">An object that supplies culture-specific formatting information.</param> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void WriteLine(IFormatProvider provider, float value) | ||||||
|  |     { | ||||||
|  |         Console.WriteLine(value.ToString(provider), CurrentStyle); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the text representation of the specified double-precision floating-point | ||||||
|  |     /// value, followed by the current line terminator, to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void WriteLine(double value) | ||||||
|  |     { | ||||||
|  |         WriteLine(CultureInfo.CurrentCulture, value); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the text representation of the specified double-precision floating-point | ||||||
|  |     /// value, followed by the current line terminator, to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="provider">An object that supplies culture-specific formatting information.</param> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void WriteLine(IFormatProvider provider, double value) | ||||||
|  |     { | ||||||
|  |         Console.WriteLine(value.ToString(provider), CurrentStyle); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the text representation of the specified decimal value, | ||||||
|  |     /// followed by the current line terminator, to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void WriteLine(decimal value) | ||||||
|  |     { | ||||||
|  |         WriteLine(CultureInfo.CurrentCulture, value); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the text representation of the specified decimal value, | ||||||
|  |     /// followed by the current line terminator, to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="provider">An object that supplies culture-specific formatting information.</param> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void WriteLine(IFormatProvider provider, decimal value) | ||||||
|  |     { | ||||||
|  |         Console.WriteLine(value.ToString(provider), CurrentStyle); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the text representation of the specified boolean value, | ||||||
|  |     /// followed by the current line terminator, to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void WriteLine(bool value) | ||||||
|  |     { | ||||||
|  |         WriteLine(CultureInfo.CurrentCulture, value); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the text representation of the specified boolean value, | ||||||
|  |     /// followed by the current line terminator, to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="provider">An object that supplies culture-specific formatting information.</param> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void WriteLine(IFormatProvider provider, bool value) | ||||||
|  |     { | ||||||
|  |         Console.WriteLine(value.ToString(provider), CurrentStyle); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the specified Unicode character, followed by the current | ||||||
|  |     /// line terminator, value to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void WriteLine(char value) | ||||||
|  |     { | ||||||
|  |         WriteLine(CultureInfo.CurrentCulture, value); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the specified Unicode character, followed by the current | ||||||
|  |     /// line terminator, value to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="provider">An object that supplies culture-specific formatting information.</param> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void WriteLine(IFormatProvider provider, char value) | ||||||
|  |     { | ||||||
|  |         Console.WriteLine(value.ToString(provider), CurrentStyle); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the specified array of Unicode characters, followed by the current | ||||||
|  |     /// line terminator, value to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     public static void WriteLine(char[] value) | ||||||
|  |     { | ||||||
|  |         WriteLine(CultureInfo.CurrentCulture, value); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the specified array of Unicode characters, followed by the current | ||||||
|  |     /// line terminator, value to the console. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="provider">An object that supplies culture-specific formatting information.</param> | ||||||
|  |     /// <param name="value">The value to write.</param> | ||||||
|  |     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(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the text representation of the specified array of objects, | ||||||
|  |     /// followed by the current line terminator, to the console | ||||||
|  |     /// using the specified format information. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="format">A composite format string.</param> | ||||||
|  |     /// <param name="args">An array of objects to write.</param> | ||||||
|  |     public static void WriteLine(string format, params object[] args) | ||||||
|  |     { | ||||||
|  |         WriteLine(CultureInfo.CurrentCulture, format, args); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Writes the text representation of the specified array of objects, | ||||||
|  |     /// followed by the current line terminator, to the console | ||||||
|  |     /// using the specified format information. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="provider">An object that supplies culture-specific formatting information.</param> | ||||||
|  |     /// <param name="format">A composite format string.</param> | ||||||
|  |     /// <param name="args">An array of objects to write.</param> | ||||||
|  |     public static void WriteLine(IFormatProvider provider, string format, params object[] args) | ||||||
|  |     { | ||||||
|  |         Console.WriteLine(string.Format(provider, format, args), CurrentStyle); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,78 +1,77 @@ | |||||||
| using System; | using System; | ||||||
|  |  | ||||||
| namespace Spectre.Console | namespace Spectre.Console; | ||||||
| { |  | ||||||
|     /// <summary> |  | ||||||
|     /// A console capable of writing ANSI escape sequences. |  | ||||||
|     /// </summary> |  | ||||||
|     public static partial class AnsiConsole |  | ||||||
|     { |  | ||||||
|         private static Recorder? _recorder; |  | ||||||
|         private static Lazy<IAnsiConsole> _console = new Lazy<IAnsiConsole>( |  | ||||||
|             () => |  | ||||||
|             { |  | ||||||
|                 var console = Create(new AnsiConsoleSettings |  | ||||||
|                 { |  | ||||||
|                     Ansi = AnsiSupport.Detect, |  | ||||||
|                     ColorSystem = ColorSystemSupport.Detect, |  | ||||||
|                     Out = new AnsiConsoleOutput(System.Console.Out), |  | ||||||
|                 }); |  | ||||||
|  |  | ||||||
|                 Created = true; | /// <summary> | ||||||
|                 return console; | /// A console capable of writing ANSI escape sequences. | ||||||
|  | /// </summary> | ||||||
|  | public static partial class AnsiConsole | ||||||
|  | { | ||||||
|  |     private static Recorder? _recorder; | ||||||
|  |     private static Lazy<IAnsiConsole> _console = new Lazy<IAnsiConsole>( | ||||||
|  |         () => | ||||||
|  |         { | ||||||
|  |             var console = Create(new AnsiConsoleSettings | ||||||
|  |             { | ||||||
|  |                 Ansi = AnsiSupport.Detect, | ||||||
|  |                 ColorSystem = ColorSystemSupport.Detect, | ||||||
|  |                 Out = new AnsiConsoleOutput(System.Console.Out), | ||||||
|             }); |             }); | ||||||
|  |  | ||||||
|         /// <summary> |             Created = true; | ||||||
|         /// Gets or sets the underlying <see cref="IAnsiConsole"/>. |             return console; | ||||||
|         /// </summary> |         }); | ||||||
|         public static IAnsiConsole Console |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Gets or sets the underlying <see cref="IAnsiConsole"/>. | ||||||
|  |     /// </summary> | ||||||
|  |     public static IAnsiConsole Console | ||||||
|  |     { | ||||||
|  |         get | ||||||
|         { |         { | ||||||
|             get |             return _recorder ?? _console.Value; | ||||||
|             { |  | ||||||
|                 return _recorder ?? _console.Value; |  | ||||||
|             } |  | ||||||
|             set |  | ||||||
|             { |  | ||||||
|                 _console = new Lazy<IAnsiConsole>(() => value); |  | ||||||
|  |  | ||||||
|                 if (_recorder != null) |  | ||||||
|                 { |  | ||||||
|                     // Recreate the recorder |  | ||||||
|                     _recorder = _recorder.Clone(value); |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 Created = true; |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|  |         set | ||||||
|         /// <summary> |  | ||||||
|         /// Gets the <see cref="IAnsiConsoleCursor"/>. |  | ||||||
|         /// </summary> |  | ||||||
|         public static IAnsiConsoleCursor Cursor => _recorder?.Cursor ?? _console.Value.Cursor; |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Gets the console profile. |  | ||||||
|         /// </summary> |  | ||||||
|         public static Profile Profile => Console.Profile; |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Creates a new <see cref="IAnsiConsole"/> instance |  | ||||||
|         /// from the provided settings. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="settings">The settings to use.</param> |  | ||||||
|         /// <returns>An <see cref="IAnsiConsole"/> instance.</returns> |  | ||||||
|         public static IAnsiConsole Create(AnsiConsoleSettings settings) |  | ||||||
|         { |         { | ||||||
|             var factory = new AnsiConsoleFactory(); |             _console = new Lazy<IAnsiConsole>(() => value); | ||||||
|             return factory.Create(settings); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <summary> |             if (_recorder != null) | ||||||
|         /// Clears the console. |             { | ||||||
|         /// </summary> |                 // Recreate the recorder | ||||||
|         public static void Clear() |                 _recorder = _recorder.Clone(value); | ||||||
|         { |             } | ||||||
|             Console.Clear(); |  | ||||||
|  |             Created = true; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Gets the <see cref="IAnsiConsoleCursor"/>. | ||||||
|  |     /// </summary> | ||||||
|  |     public static IAnsiConsoleCursor Cursor => _recorder?.Cursor ?? _console.Value.Cursor; | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Gets the console profile. | ||||||
|  |     /// </summary> | ||||||
|  |     public static Profile Profile => Console.Profile; | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Creates a new <see cref="IAnsiConsole"/> instance | ||||||
|  |     /// from the provided settings. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="settings">The settings to use.</param> | ||||||
|  |     /// <returns>An <see cref="IAnsiConsole"/> instance.</returns> | ||||||
|  |     public static IAnsiConsole Create(AnsiConsoleSettings settings) | ||||||
|  |     { | ||||||
|  |         var factory = new AnsiConsoleFactory(); | ||||||
|  |         return factory.Create(settings); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Clears the console. | ||||||
|  |     /// </summary> | ||||||
|  |     public static void Clear() | ||||||
|  |     { | ||||||
|  |         Console.Clear(); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -3,110 +3,109 @@ using System.Runtime.InteropServices; | |||||||
| using Spectre.Console.Enrichment; | using Spectre.Console.Enrichment; | ||||||
| using Spectre.Console.Internal; | using Spectre.Console.Internal; | ||||||
|  |  | ||||||
| namespace Spectre.Console | namespace Spectre.Console; | ||||||
|  |  | ||||||
|  | /// <summary> | ||||||
|  | /// Factory for creating an ANSI console. | ||||||
|  | /// </summary> | ||||||
|  | public sealed class AnsiConsoleFactory | ||||||
| { | { | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// Factory for creating an ANSI console. |     /// Creates an ANSI console. | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     public sealed class AnsiConsoleFactory |     /// <param name="settings">The settings.</param> | ||||||
|  |     /// <returns>An implementation of <see cref="IAnsiConsole"/>.</returns> | ||||||
|  |     public IAnsiConsole Create(AnsiConsoleSettings settings) | ||||||
|     { |     { | ||||||
|         /// <summary> |         if (settings is null) | ||||||
|         /// Creates an ANSI console. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="settings">The settings.</param> |  | ||||||
|         /// <returns>An implementation of <see cref="IAnsiConsole"/>.</returns> |  | ||||||
|         public IAnsiConsole Create(AnsiConsoleSettings settings) |  | ||||||
|         { |         { | ||||||
|             if (settings is null) |             throw new ArgumentNullException(nameof(settings)); | ||||||
|             { |  | ||||||
|                 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()); |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         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; |             throw new InvalidOperationException("Output writer was null"); | ||||||
|             var legacyConsole = false; |         } | ||||||
|  |  | ||||||
|             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); |                 legacyConsole = AnsiConsole.Profile.Capabilities.Legacy; | ||||||
|  |  | ||||||
|                 // 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; |  | ||||||
|                 } |  | ||||||
|             } |             } | ||||||
|             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? |                     // Not the first console we're creating? | ||||||
|                     if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) |                     if (AnsiConsole.Created) | ||||||
|                     { |                     { | ||||||
|                         // Not the first console we're creating? |                         legacyConsole = AnsiConsole.Profile.Capabilities.Legacy; | ||||||
|                         if (AnsiConsole.Created) |                     } | ||||||
|                         { |                     else | ||||||
|                             legacyConsole = AnsiConsole.Profile.Capabilities.Legacy; |                     { | ||||||
|                         } |                         // Try detecting whether or not this is a legacy console | ||||||
|                         else |                         (_, legacyConsole) = AnsiDetector.Detect(buffer.IsStandardError(), false); | ||||||
|                         { |  | ||||||
|                             // Try detecting whether or not this is a legacy console |  | ||||||
|                             (_, legacyConsole) = AnsiDetector.Detect(buffer.IsStandardError(), false); |  | ||||||
|                         } |  | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             return (supportsAnsi, legacyConsole); |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         return (supportsAnsi, legacyConsole); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -2,57 +2,56 @@ using System; | |||||||
| using System.IO; | using System.IO; | ||||||
| using System.Text; | using System.Text; | ||||||
|  |  | ||||||
| namespace Spectre.Console | namespace Spectre.Console; | ||||||
|  |  | ||||||
|  | /// <summary> | ||||||
|  | /// Represents console output. | ||||||
|  | /// </summary> | ||||||
|  | public sealed class AnsiConsoleOutput : IAnsiConsoleOutput | ||||||
| { | { | ||||||
|     /// <summary> |     /// <inheritdoc/> | ||||||
|     /// Represents console output. |     public TextWriter Writer { get; } | ||||||
|     /// </summary> |  | ||||||
|     public sealed class AnsiConsoleOutput : IAnsiConsoleOutput |     /// <inheritdoc/> | ||||||
|  |     public bool IsTerminal | ||||||
|     { |     { | ||||||
|         /// <inheritdoc/> |         get | ||||||
|         public TextWriter Writer { get; } |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         public bool IsTerminal |  | ||||||
|         { |         { | ||||||
|             get |             if (Writer.IsStandardOut()) | ||||||
|             { |             { | ||||||
|                 if (Writer.IsStandardOut()) |                 return !System.Console.IsOutputRedirected; | ||||||
|                 { |  | ||||||
|                     return !System.Console.IsOutputRedirected; |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 if (Writer.IsStandardError()) |  | ||||||
|                 { |  | ||||||
|                     return !System.Console.IsErrorRedirected; |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 return false; |  | ||||||
|             } |             } | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |             if (Writer.IsStandardError()) | ||||||
|         public int Width => ConsoleHelper.GetSafeWidth(Constants.DefaultTerminalWidth); |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         public int Height => ConsoleHelper.GetSafeHeight(Constants.DefaultTerminalWidth); |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Initializes a new instance of the <see cref="AnsiConsoleOutput"/> class. |  | ||||||
|         /// </summary> |  | ||||||
|         /// <param name="writer">The output writer.</param> |  | ||||||
|         public AnsiConsoleOutput(TextWriter writer) |  | ||||||
|         { |  | ||||||
|             Writer = writer ?? throw new ArgumentNullException(nameof(writer)); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         /// <inheritdoc/> |  | ||||||
|         public void SetEncoding(Encoding encoding) |  | ||||||
|         { |  | ||||||
|             if (Writer.IsStandardOut() || Writer.IsStandardError()) |  | ||||||
|             { |             { | ||||||
|                 System.Console.OutputEncoding = encoding; |                 return !System.Console.IsErrorRedirected; | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  |             return false; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } |  | ||||||
|  |     /// <inheritdoc/> | ||||||
|  |     public int Width => ConsoleHelper.GetSafeWidth(Constants.DefaultTerminalWidth); | ||||||
|  |  | ||||||
|  |     /// <inheritdoc/> | ||||||
|  |     public int Height => ConsoleHelper.GetSafeHeight(Constants.DefaultTerminalWidth); | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Initializes a new instance of the <see cref="AnsiConsoleOutput"/> class. | ||||||
|  |     /// </summary> | ||||||
|  |     /// <param name="writer">The output writer.</param> | ||||||
|  |     public AnsiConsoleOutput(TextWriter writer) | ||||||
|  |     { | ||||||
|  |         Writer = writer ?? throw new ArgumentNullException(nameof(writer)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /// <inheritdoc/> | ||||||
|  |     public void SetEncoding(Encoding encoding) | ||||||
|  |     { | ||||||
|  |         if (Writer.IsStandardOut() || Writer.IsStandardError()) | ||||||
|  |         { | ||||||
|  |             System.Console.OutputEncoding = encoding; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -1,56 +1,55 @@ | |||||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||||
|  |  | ||||||
| namespace Spectre.Console | namespace Spectre.Console; | ||||||
|  |  | ||||||
|  | /// <summary> | ||||||
|  | /// Settings used when building a <see cref="IAnsiConsole"/>. | ||||||
|  | /// </summary> | ||||||
|  | public sealed class AnsiConsoleSettings | ||||||
| { | { | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// Settings used when building a <see cref="IAnsiConsole"/>. |     /// Gets or sets a value indicating whether or | ||||||
|  |     /// not ANSI escape sequences are supported. | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     public sealed class AnsiConsoleSettings |     public AnsiSupport Ansi { get; set; } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Gets or sets the color system to use. | ||||||
|  |     /// </summary> | ||||||
|  |     public ColorSystemSupport ColorSystem { get; set; } = ColorSystemSupport.Detect; | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Gets or sets the out buffer. | ||||||
|  |     /// </summary> | ||||||
|  |     public IAnsiConsoleOutput? Out { get; set; } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Gets or sets a value indicating whether or not the | ||||||
|  |     /// terminal is interactive or not. | ||||||
|  |     /// </summary> | ||||||
|  |     public InteractionSupport Interactive { get; set; } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Gets or sets the exclusivity mode. | ||||||
|  |     /// </summary> | ||||||
|  |     public IExclusivityMode? ExclusivityMode { get; set; } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Gets or sets the profile enrichments settings. | ||||||
|  |     /// </summary> | ||||||
|  |     public ProfileEnrichment Enrichment { get; set; } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Gets or sets the environment variables. | ||||||
|  |     /// If not value is provided the default environment variables will be used. | ||||||
|  |     /// </summary> | ||||||
|  |     public Dictionary<string, string>? EnvironmentVariables { get; set; } | ||||||
|  |  | ||||||
|  |     /// <summary> | ||||||
|  |     /// Initializes a new instance of the <see cref="AnsiConsoleSettings"/> class. | ||||||
|  |     /// </summary> | ||||||
|  |     public AnsiConsoleSettings() | ||||||
|     { |     { | ||||||
|         /// <summary> |         Enrichment = new ProfileEnrichment(); | ||||||
|         /// Gets or sets a value indicating whether or |  | ||||||
|         /// not ANSI escape sequences are supported. |  | ||||||
|         /// </summary> |  | ||||||
|         public AnsiSupport Ansi { get; set; } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Gets or sets the color system to use. |  | ||||||
|         /// </summary> |  | ||||||
|         public ColorSystemSupport ColorSystem { get; set; } = ColorSystemSupport.Detect; |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Gets or sets the out buffer. |  | ||||||
|         /// </summary> |  | ||||||
|         public IAnsiConsoleOutput? Out { get; set; } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Gets or sets a value indicating whether or not the |  | ||||||
|         /// terminal is interactive or not. |  | ||||||
|         /// </summary> |  | ||||||
|         public InteractionSupport Interactive { get; set; } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Gets or sets the exclusivity mode. |  | ||||||
|         /// </summary> |  | ||||||
|         public IExclusivityMode? ExclusivityMode { get; set; } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Gets or sets the profile enrichments settings. |  | ||||||
|         /// </summary> |  | ||||||
|         public ProfileEnrichment Enrichment { get; set; } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Gets or sets the environment variables. |  | ||||||
|         /// If not value is provided the default environment variables will be used. |  | ||||||
|         /// </summary> |  | ||||||
|         public Dictionary<string, string>? EnvironmentVariables { get; set; } |  | ||||||
|  |  | ||||||
|         /// <summary> |  | ||||||
|         /// Initializes a new instance of the <see cref="AnsiConsoleSettings"/> class. |  | ||||||
|         /// </summary> |  | ||||||
|         public AnsiConsoleSettings() |  | ||||||
|         { |  | ||||||
|             Enrichment = new ProfileEnrichment(); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -1,24 +1,23 @@ | |||||||
| namespace Spectre.Console | namespace Spectre.Console; | ||||||
|  |  | ||||||
|  | /// <summary> | ||||||
|  | /// Determines ANSI escape sequence support. | ||||||
|  | /// </summary> | ||||||
|  | public enum AnsiSupport | ||||||
| { | { | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// Determines ANSI escape sequence support. |     /// ANSI escape sequence support should | ||||||
|  |     /// be detected by the system. | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     public enum AnsiSupport |     Detect = 0, | ||||||
|     { |  | ||||||
|         /// <summary> |  | ||||||
|         /// ANSI escape sequence support should |  | ||||||
|         /// be detected by the system. |  | ||||||
|         /// </summary> |  | ||||||
|         Detect = 0, |  | ||||||
|  |  | ||||||
|         /// <summary> |     /// <summary> | ||||||
|         /// ANSI escape sequences are supported. |     /// ANSI escape sequences are supported. | ||||||
|         /// </summary> |     /// </summary> | ||||||
|         Yes = 1, |     Yes = 1, | ||||||
|  |  | ||||||
|         /// <summary> |     /// <summary> | ||||||
|         /// ANSI escape sequences are not supported. |     /// ANSI escape sequences are not supported. | ||||||
|         /// </summary> |     /// </summary> | ||||||
|         No = 2, |     No = 2, | ||||||
|     } | } | ||||||
| } |  | ||||||
| @@ -1,42 +1,41 @@ | |||||||
| using System.Diagnostics.CodeAnalysis; | using System.Diagnostics.CodeAnalysis; | ||||||
| using Spectre.Console.Rendering; | using Spectre.Console.Rendering; | ||||||
|  |  | ||||||
| namespace Spectre.Console | namespace Spectre.Console; | ||||||
|  |  | ||||||
|  | /// <summary> | ||||||
|  | /// Represents a border. | ||||||
|  | /// </summary> | ||||||
|  | public abstract partial class BoxBorder | ||||||
| { | { | ||||||
|     /// <summary> |     /// <summary> | ||||||
|     /// Represents a border. |     /// Gets an invisible border. | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     public abstract partial class BoxBorder |     public static BoxBorder None { get; } = new NoBoxBorder(); | ||||||
|     { |  | ||||||
|         /// <summary> |  | ||||||
|         /// Gets an invisible border. |  | ||||||
|         /// </summary> |  | ||||||
|         public static BoxBorder None { get; } = new NoBoxBorder(); |  | ||||||
|  |  | ||||||
|         /// <summary> |     /// <summary> | ||||||
|         /// Gets an ASCII border. |     /// Gets an ASCII border. | ||||||
|         /// </summary> |     /// </summary> | ||||||
|         public static BoxBorder Ascii { get; } = new AsciiBoxBorder(); |     public static BoxBorder Ascii { get; } = new AsciiBoxBorder(); | ||||||
|  |  | ||||||
|         /// <summary> |     /// <summary> | ||||||
|         /// Gets a double border. |     /// Gets a double border. | ||||||
|         /// </summary> |     /// </summary> | ||||||
|         [SuppressMessage("Naming", "CA1720:Identifier contains type name")] |     [SuppressMessage("Naming", "CA1720:Identifier contains type name")] | ||||||
|         public static BoxBorder Double { get; } = new DoubleBoxBorder(); |     public static BoxBorder Double { get; } = new DoubleBoxBorder(); | ||||||
|  |  | ||||||
|         /// <summary> |     /// <summary> | ||||||
|         /// Gets a heavy border. |     /// Gets a heavy border. | ||||||
|         /// </summary> |     /// </summary> | ||||||
|         public static BoxBorder Heavy { get; } = new HeavyBoxBorder(); |     public static BoxBorder Heavy { get; } = new HeavyBoxBorder(); | ||||||
|  |  | ||||||
|         /// <summary> |     /// <summary> | ||||||
|         /// Gets a rounded border. |     /// Gets a rounded border. | ||||||
|         /// </summary> |     /// </summary> | ||||||
|         public static BoxBorder Rounded { get; } = new RoundedBoxBorder(); |     public static BoxBorder Rounded { get; } = new RoundedBoxBorder(); | ||||||
|  |  | ||||||
|         /// <summary> |     /// <summary> | ||||||
|         /// Gets a square border. |     /// Gets a square border. | ||||||
|         /// </summary> |     /// </summary> | ||||||
|         public static BoxBorder Square { get; } = new SquareBoxBorder(); |     public static BoxBorder Square { get; } = new SquareBoxBorder(); | ||||||
|     } | } | ||||||
| } |  | ||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user