mirror of
				https://github.com/nsnail/spectre.console.git
				synced 2025-11-01 01:25:27 +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
				
			| @@ -1,7 +1,7 @@ | ||||
| <Project> | ||||
|   <PropertyGroup Label="Settings"> | ||||
|     <Deterministic>true</Deterministic> | ||||
|     <LangVersion>9.0</LangVersion> | ||||
|     <LangVersion>10</LangVersion> | ||||
|     <DebugSymbols>true</DebugSymbols> | ||||
|     <DebugType>embedded</DebugType> | ||||
|     <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> | ||||
|     /// Sample sandbox for testing out analyzers. | ||||
|     /// The program's entry point. | ||||
|     /// </summary> | ||||
|     public static class Program | ||||
|     public static void Main() | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// The program's entry point. | ||||
|         /// </summary> | ||||
|         public static void Main() | ||||
|         { | ||||
|             AnsiConsole.WriteLine("Project is set up with a reference to Spectre.Console.Analyzer"); | ||||
|         } | ||||
|         AnsiConsole.WriteLine("Project is set up with a reference to Spectre.Console.Analyzer"); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -6,90 +6,89 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; | ||||
| using Microsoft.CodeAnalysis.Diagnostics; | ||||
| using Microsoft.CodeAnalysis.Operations; | ||||
|  | ||||
| namespace Spectre.Console.Analyzer | ||||
| namespace Spectre.Console.Analyzer; | ||||
|  | ||||
| /// <summary> | ||||
| /// Analyzer to suggest using available instances of AnsiConsole over the static methods. | ||||
| /// </summary> | ||||
| [DiagnosticAnalyzer(LanguageNames.CSharp)] | ||||
| public class FavorInstanceAnsiConsoleOverStaticAnalyzer : SpectreAnalyzer | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Analyzer to suggest using available instances of AnsiConsole over the static methods. | ||||
|     /// </summary> | ||||
|     [DiagnosticAnalyzer(LanguageNames.CSharp)] | ||||
|     public class FavorInstanceAnsiConsoleOverStaticAnalyzer : SpectreAnalyzer | ||||
|     private static readonly DiagnosticDescriptor _diagnosticDescriptor = | ||||
|         Descriptors.S1010_FavorInstanceAnsiConsoleOverStatic; | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => | ||||
|         ImmutableArray.Create(_diagnosticDescriptor); | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     protected override void AnalyzeCompilation(CompilationStartAnalysisContext compilationStartContext) | ||||
|     { | ||||
|         private static readonly DiagnosticDescriptor _diagnosticDescriptor = | ||||
|             Descriptors.S1010_FavorInstanceAnsiConsoleOverStatic; | ||||
|         compilationStartContext.RegisterOperationAction( | ||||
|             context => | ||||
|             { | ||||
|                 var ansiConsoleType = context.Compilation.GetTypeByMetadataName("Spectre.Console.AnsiConsole"); | ||||
|  | ||||
|         /// <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 | ||||
|                 // defined in _methods then we can safely stop analyzing and return; | ||||
|                 var invocationOperation = (IInvocationOperation)context.Operation; | ||||
|                 if (!Equals(invocationOperation.TargetMethod.ContainingType, ansiConsoleType)) | ||||
|                 { | ||||
|                     var ansiConsoleType = context.Compilation.GetTypeByMetadataName("Spectre.Console.AnsiConsole"); | ||||
|                     return; | ||||
|                 } | ||||
|  | ||||
|                     // if this operation isn't an invocation against one of the System.Console methods | ||||
|                     // defined in _methods then we can safely stop analyzing and return; | ||||
|                     var invocationOperation = (IInvocationOperation)context.Operation; | ||||
|                     if (!Equals(invocationOperation.TargetMethod.ContainingType, ansiConsoleType)) | ||||
|                     { | ||||
|                         return; | ||||
|                     } | ||||
|                 // if we aren't in a method then it might be too complex for us to handle. | ||||
|                 if (!invocationOperation.Syntax.Ancestors().OfType<MethodDeclarationSyntax>().Any()) | ||||
|                 { | ||||
|                     return; | ||||
|                 } | ||||
|  | ||||
|                     // if we aren't in a method then it might be too complex for us to handle. | ||||
|                     if (!invocationOperation.Syntax.Ancestors().OfType<MethodDeclarationSyntax>().Any()) | ||||
|                     { | ||||
|                         return; | ||||
|                     } | ||||
|                 if (!HasFieldAnsiConsole(invocationOperation.Syntax) && | ||||
|                     !HasParameterAnsiConsole(invocationOperation.Syntax)) | ||||
|                 { | ||||
|                     return; | ||||
|                 } | ||||
|  | ||||
|                     if (!HasFieldAnsiConsole(invocationOperation.Syntax) && | ||||
|                         !HasParameterAnsiConsole(invocationOperation.Syntax)) | ||||
|                     { | ||||
|                         return; | ||||
|                     } | ||||
|                 var methodSymbol = invocationOperation.TargetMethod; | ||||
|  | ||||
|                     var methodSymbol = invocationOperation.TargetMethod; | ||||
|                 var displayString = SymbolDisplay.ToDisplayString( | ||||
|                     methodSymbol, | ||||
|                     SymbolDisplayFormat.CSharpShortErrorMessageFormat | ||||
|                         .WithParameterOptions(SymbolDisplayParameterOptions.None) | ||||
|                         .WithGenericsOptions(SymbolDisplayGenericsOptions.None)); | ||||
|  | ||||
|                     var displayString = SymbolDisplay.ToDisplayString( | ||||
|                         methodSymbol, | ||||
|                         SymbolDisplayFormat.CSharpShortErrorMessageFormat | ||||
|                             .WithParameterOptions(SymbolDisplayParameterOptions.None) | ||||
|                             .WithGenericsOptions(SymbolDisplayGenericsOptions.None)); | ||||
|  | ||||
|                     context.ReportDiagnostic( | ||||
|                         Diagnostic.Create( | ||||
|                             _diagnosticDescriptor, | ||||
|                             invocationOperation.Syntax.GetLocation(), | ||||
|                             displayString)); | ||||
|                 }, OperationKind.Invocation); | ||||
|         } | ||||
|  | ||||
|         private static bool HasParameterAnsiConsole(SyntaxNode syntaxNode) | ||||
|         { | ||||
|             return syntaxNode | ||||
|                 .Ancestors().OfType<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))); | ||||
|         } | ||||
|                 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))); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -7,72 +7,71 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; | ||||
| using Microsoft.CodeAnalysis.Diagnostics; | ||||
| using Microsoft.CodeAnalysis.Operations; | ||||
|  | ||||
| namespace Spectre.Console.Analyzer | ||||
| namespace Spectre.Console.Analyzer; | ||||
|  | ||||
| /// <summary> | ||||
| /// Analyzer to detect calls to live renderables within a live renderable context. | ||||
| /// </summary> | ||||
| [DiagnosticAnalyzer(LanguageNames.CSharp)] | ||||
| [Shared] | ||||
| public class NoConcurrentLiveRenderablesAnalyzer : SpectreAnalyzer | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Analyzer to detect calls to live renderables within a live renderable context. | ||||
|     /// </summary> | ||||
|     [DiagnosticAnalyzer(LanguageNames.CSharp)] | ||||
|     [Shared] | ||||
|     public class NoConcurrentLiveRenderablesAnalyzer : SpectreAnalyzer | ||||
|     private static readonly DiagnosticDescriptor _diagnosticDescriptor = | ||||
|         Descriptors.S1020_AvoidConcurrentCallsToMultipleLiveRenderables; | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => | ||||
|         ImmutableArray.Create(_diagnosticDescriptor); | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     protected override void AnalyzeCompilation(CompilationStartAnalysisContext compilationStartContext) | ||||
|     { | ||||
|         private static readonly DiagnosticDescriptor _diagnosticDescriptor = | ||||
|             Descriptors.S1020_AvoidConcurrentCallsToMultipleLiveRenderables; | ||||
|         compilationStartContext.RegisterOperationAction( | ||||
|             context => | ||||
|             { | ||||
|                 var invocationOperation = (IInvocationOperation)context.Operation; | ||||
|                 var methodSymbol = invocationOperation.TargetMethod; | ||||
|  | ||||
|         /// <inheritdoc /> | ||||
|         public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => | ||||
|             ImmutableArray.Create(_diagnosticDescriptor); | ||||
|  | ||||
|         /// <inheritdoc /> | ||||
|         protected override void AnalyzeCompilation(CompilationStartAnalysisContext compilationStartContext) | ||||
|         { | ||||
|             compilationStartContext.RegisterOperationAction( | ||||
|                 context => | ||||
|                 const string StartMethod = "Start"; | ||||
|                 if (methodSymbol.Name != StartMethod) | ||||
|                 { | ||||
|                     var invocationOperation = (IInvocationOperation)context.Operation; | ||||
|                     var methodSymbol = invocationOperation.TargetMethod; | ||||
|                     return; | ||||
|                 } | ||||
|  | ||||
|                     const string StartMethod = "Start"; | ||||
|                     if (methodSymbol.Name != StartMethod) | ||||
|                     { | ||||
|                         return; | ||||
|                     } | ||||
|                 var liveTypes = Constants.LiveRenderables | ||||
|                     .Select(i => context.Compilation.GetTypeByMetadataName(i)) | ||||
|                     .ToImmutableArray(); | ||||
|  | ||||
|                     var liveTypes = Constants.LiveRenderables | ||||
|                         .Select(i => context.Compilation.GetTypeByMetadataName(i)) | ||||
|                         .ToImmutableArray(); | ||||
|                 if (liveTypes.All(i => !Equals(i, methodSymbol.ContainingType))) | ||||
|                 { | ||||
|                     return; | ||||
|                 } | ||||
|  | ||||
|                     if (liveTypes.All(i => !Equals(i, methodSymbol.ContainingType))) | ||||
|                     { | ||||
|                         return; | ||||
|                     } | ||||
|                 var model = context.Compilation.GetSemanticModel(context.Operation.Syntax.SyntaxTree); | ||||
|                 var parentInvocations = invocationOperation | ||||
|                     .Syntax.Ancestors() | ||||
|                     .OfType<InvocationExpressionSyntax>() | ||||
|                     .Select(i => model.GetOperation(i)) | ||||
|                     .OfType<IInvocationOperation>() | ||||
|                     .ToList(); | ||||
|  | ||||
|                     var model = context.Compilation.GetSemanticModel(context.Operation.Syntax.SyntaxTree); | ||||
|                     var parentInvocations = invocationOperation | ||||
|                         .Syntax.Ancestors() | ||||
|                         .OfType<InvocationExpressionSyntax>() | ||||
|                         .Select(i => model.GetOperation(i)) | ||||
|                         .OfType<IInvocationOperation>() | ||||
|                         .ToList(); | ||||
|                 if (parentInvocations.All(parent => | ||||
|                     parent.TargetMethod.Name != StartMethod || !liveTypes.Contains(parent.TargetMethod.ContainingType))) | ||||
|                 { | ||||
|                     return; | ||||
|                 } | ||||
|  | ||||
|                     if (parentInvocations.All(parent => | ||||
|                         parent.TargetMethod.Name != StartMethod || !liveTypes.Contains(parent.TargetMethod.ContainingType))) | ||||
|                     { | ||||
|                         return; | ||||
|                     } | ||||
|                 var displayString = SymbolDisplay.ToDisplayString( | ||||
|                     methodSymbol, | ||||
|                     SymbolDisplayFormat.CSharpShortErrorMessageFormat | ||||
|                         .WithParameterOptions(SymbolDisplayParameterOptions.None) | ||||
|                         .WithGenericsOptions(SymbolDisplayGenericsOptions.None)); | ||||
|  | ||||
|                     var displayString = SymbolDisplay.ToDisplayString( | ||||
|                         methodSymbol, | ||||
|                         SymbolDisplayFormat.CSharpShortErrorMessageFormat | ||||
|                             .WithParameterOptions(SymbolDisplayParameterOptions.None) | ||||
|                             .WithGenericsOptions(SymbolDisplayGenericsOptions.None)); | ||||
|  | ||||
|                     context.ReportDiagnostic( | ||||
|                         Diagnostic.Create( | ||||
|                             _diagnosticDescriptor, | ||||
|                             invocationOperation.Syntax.GetLocation(), | ||||
|                             displayString)); | ||||
|                 }, OperationKind.Invocation); | ||||
|         } | ||||
|                 context.ReportDiagnostic( | ||||
|                     Diagnostic.Create( | ||||
|                         _diagnosticDescriptor, | ||||
|                         invocationOperation.Syntax.GetLocation(), | ||||
|                         displayString)); | ||||
|             }, OperationKind.Invocation); | ||||
|     } | ||||
| } | ||||
| } | ||||
|   | ||||
| @@ -7,78 +7,77 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; | ||||
| using Microsoft.CodeAnalysis.Diagnostics; | ||||
| using Microsoft.CodeAnalysis.Operations; | ||||
|  | ||||
| namespace Spectre.Console.Analyzer | ||||
| namespace Spectre.Console.Analyzer; | ||||
|  | ||||
| /// <summary> | ||||
| /// Analyzer to detect calls to live renderables within a live renderable context. | ||||
| /// </summary> | ||||
| [DiagnosticAnalyzer(LanguageNames.CSharp)] | ||||
| [Shared] | ||||
| public class NoPromptsDuringLiveRenderablesAnalyzer : SpectreAnalyzer | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Analyzer to detect calls to live renderables within a live renderable context. | ||||
|     /// </summary> | ||||
|     [DiagnosticAnalyzer(LanguageNames.CSharp)] | ||||
|     [Shared] | ||||
|     public class NoPromptsDuringLiveRenderablesAnalyzer : SpectreAnalyzer | ||||
|     private static readonly DiagnosticDescriptor _diagnosticDescriptor = | ||||
|         Descriptors.S1021_AvoidPromptCallsDuringLiveRenderables; | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => | ||||
|         ImmutableArray.Create(_diagnosticDescriptor); | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     protected override void AnalyzeCompilation(CompilationStartAnalysisContext compilationStartContext) | ||||
|     { | ||||
|         private static readonly DiagnosticDescriptor _diagnosticDescriptor = | ||||
|             Descriptors.S1021_AvoidPromptCallsDuringLiveRenderables; | ||||
|         compilationStartContext.RegisterOperationAction( | ||||
|             context => | ||||
|             { | ||||
|                 // if this operation isn't an invocation against one of the System.Console methods | ||||
|                 // defined in _methods then we can safely stop analyzing and return; | ||||
|                 var invocationOperation = (IInvocationOperation)context.Operation; | ||||
|                 var methodSymbol = invocationOperation.TargetMethod; | ||||
|  | ||||
|         /// <inheritdoc /> | ||||
|         public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => | ||||
|             ImmutableArray.Create(_diagnosticDescriptor); | ||||
|  | ||||
|         /// <inheritdoc /> | ||||
|         protected override void AnalyzeCompilation(CompilationStartAnalysisContext compilationStartContext) | ||||
|         { | ||||
|             compilationStartContext.RegisterOperationAction( | ||||
|                 context => | ||||
|                 var promptMethods = ImmutableArray.Create("Ask", "Confirm", "Prompt"); | ||||
|                 if (!promptMethods.Contains(methodSymbol.Name)) | ||||
|                 { | ||||
|                     // if this operation isn't an invocation against one of the System.Console methods | ||||
|                     // defined in _methods then we can safely stop analyzing and return; | ||||
|                     var invocationOperation = (IInvocationOperation)context.Operation; | ||||
|                     var methodSymbol = invocationOperation.TargetMethod; | ||||
|                     return; | ||||
|                 } | ||||
|  | ||||
|                     var promptMethods = ImmutableArray.Create("Ask", "Confirm", "Prompt"); | ||||
|                     if (!promptMethods.Contains(methodSymbol.Name)) | ||||
|                     { | ||||
|                         return; | ||||
|                     } | ||||
|                 var ansiConsoleType = context.Compilation.GetTypeByMetadataName("Spectre.Console.AnsiConsole"); | ||||
|                 var ansiConsoleExtensionsType = context.Compilation.GetTypeByMetadataName("Spectre.Console.AnsiConsoleExtensions"); | ||||
|  | ||||
|                     var ansiConsoleType = context.Compilation.GetTypeByMetadataName("Spectre.Console.AnsiConsole"); | ||||
|                     var ansiConsoleExtensionsType = context.Compilation.GetTypeByMetadataName("Spectre.Console.AnsiConsoleExtensions"); | ||||
|                 if (!Equals(methodSymbol.ContainingType, ansiConsoleType) && !Equals(methodSymbol.ContainingType, ansiConsoleExtensionsType)) | ||||
|                 { | ||||
|                     return; | ||||
|                 } | ||||
|  | ||||
|                     if (!Equals(methodSymbol.ContainingType, ansiConsoleType) && !Equals(methodSymbol.ContainingType, ansiConsoleExtensionsType)) | ||||
|                     { | ||||
|                         return; | ||||
|                     } | ||||
|                 var model = context.Compilation.GetSemanticModel(context.Operation.Syntax.SyntaxTree); | ||||
|                 var parentInvocations = invocationOperation | ||||
|                     .Syntax.Ancestors() | ||||
|                     .OfType<InvocationExpressionSyntax>() | ||||
|                     .Select(i => model.GetOperation(i)) | ||||
|                     .OfType<IInvocationOperation>() | ||||
|                     .ToList(); | ||||
|  | ||||
|                     var model = context.Compilation.GetSemanticModel(context.Operation.Syntax.SyntaxTree); | ||||
|                     var parentInvocations = invocationOperation | ||||
|                         .Syntax.Ancestors() | ||||
|                         .OfType<InvocationExpressionSyntax>() | ||||
|                         .Select(i => model.GetOperation(i)) | ||||
|                         .OfType<IInvocationOperation>() | ||||
|                         .ToList(); | ||||
|                 var liveTypes = Constants.LiveRenderables | ||||
|                     .Select(i => context.Compilation.GetTypeByMetadataName(i)) | ||||
|                     .ToImmutableArray(); | ||||
|  | ||||
|                     var liveTypes = Constants.LiveRenderables | ||||
|                         .Select(i => context.Compilation.GetTypeByMetadataName(i)) | ||||
|                         .ToImmutableArray(); | ||||
|                 if (parentInvocations.All(parent => | ||||
|                     parent.TargetMethod.Name != "Start" || | ||||
|                     !liveTypes.Contains(parent.TargetMethod.ContainingType))) | ||||
|                 { | ||||
|                     return; | ||||
|                 } | ||||
|  | ||||
|                     if (parentInvocations.All(parent => | ||||
|                         parent.TargetMethod.Name != "Start" || | ||||
|                         !liveTypes.Contains(parent.TargetMethod.ContainingType))) | ||||
|                     { | ||||
|                         return; | ||||
|                     } | ||||
|                 var displayString = SymbolDisplay.ToDisplayString( | ||||
|                     methodSymbol, | ||||
|                     SymbolDisplayFormat.CSharpShortErrorMessageFormat | ||||
|                         .WithParameterOptions(SymbolDisplayParameterOptions.None) | ||||
|                         .WithGenericsOptions(SymbolDisplayGenericsOptions.None)); | ||||
|  | ||||
|                     var displayString = SymbolDisplay.ToDisplayString( | ||||
|                         methodSymbol, | ||||
|                         SymbolDisplayFormat.CSharpShortErrorMessageFormat | ||||
|                             .WithParameterOptions(SymbolDisplayParameterOptions.None) | ||||
|                             .WithGenericsOptions(SymbolDisplayGenericsOptions.None)); | ||||
|  | ||||
|                     context.ReportDiagnostic( | ||||
|                         Diagnostic.Create( | ||||
|                             _diagnosticDescriptor, | ||||
|                             invocationOperation.Syntax.GetLocation(), | ||||
|                             displayString)); | ||||
|                 }, OperationKind.Invocation); | ||||
|         } | ||||
|                 context.ReportDiagnostic( | ||||
|                     Diagnostic.Create( | ||||
|                         _diagnosticDescriptor, | ||||
|                         invocationOperation.Syntax.GetLocation(), | ||||
|                         displayString)); | ||||
|             }, OperationKind.Invocation); | ||||
|     } | ||||
| } | ||||
| } | ||||
|   | ||||
| @@ -1,25 +1,24 @@ | ||||
| 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> | ||||
|     /// Base class for Spectre analyzers. | ||||
|     /// </summary> | ||||
|     public abstract class SpectreAnalyzer : DiagnosticAnalyzer | ||||
|     /// <inheritdoc /> | ||||
|     public override void Initialize(AnalysisContext context) | ||||
|     { | ||||
|         /// <inheritdoc /> | ||||
|         public override void Initialize(AnalysisContext context) | ||||
|         { | ||||
|             context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); | ||||
|             context.EnableConcurrentExecution(); | ||||
|         context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); | ||||
|         context.EnableConcurrentExecution(); | ||||
|  | ||||
|             context.RegisterCompilationStartAction(AnalyzeCompilation); | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Analyze compilation. | ||||
|         /// </summary> | ||||
|         /// <param name="compilationStartContext">Compilation Start Analysis Context.</param> | ||||
|         protected abstract void AnalyzeCompilation(CompilationStartAnalysisContext compilationStartContext); | ||||
|         context.RegisterCompilationStartAction(AnalyzeCompilation); | ||||
|     } | ||||
| } | ||||
|  | ||||
|     /// <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.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> | ||||
|     /// Analyzer to enforce the use of AnsiConsole over System.Console for known methods. | ||||
|     /// </summary> | ||||
|     [DiagnosticAnalyzer(LanguageNames.CSharp)] | ||||
|     public class UseSpectreInsteadOfSystemConsoleAnalyzer : SpectreAnalyzer | ||||
|     private static readonly DiagnosticDescriptor _diagnosticDescriptor = | ||||
|         Descriptors.S1000_UseAnsiConsoleOverSystemConsole; | ||||
|  | ||||
|     private static readonly string[] _methods = { "WriteLine", "Write" }; | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => | ||||
|         ImmutableArray.Create(_diagnosticDescriptor); | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     protected override void AnalyzeCompilation(CompilationStartAnalysisContext compilationStartContext) | ||||
|     { | ||||
|         private static readonly DiagnosticDescriptor _diagnosticDescriptor = | ||||
|             Descriptors.S1000_UseAnsiConsoleOverSystemConsole; | ||||
|         compilationStartContext.RegisterOperationAction( | ||||
|             context => | ||||
|             { | ||||
|                 // if this operation isn't an invocation against one of the System.Console methods | ||||
|                 // defined in _methods then we can safely stop analyzing and return; | ||||
|                 var invocationOperation = (IInvocationOperation)context.Operation; | ||||
|  | ||||
|         private static readonly string[] _methods = { "WriteLine", "Write" }; | ||||
|  | ||||
|         /// <inheritdoc /> | ||||
|         public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => | ||||
|             ImmutableArray.Create(_diagnosticDescriptor); | ||||
|  | ||||
|         /// <inheritdoc /> | ||||
|         protected override void AnalyzeCompilation(CompilationStartAnalysisContext compilationStartContext) | ||||
|         { | ||||
|             compilationStartContext.RegisterOperationAction( | ||||
|                 context => | ||||
|                 var methodName = System.Array.Find(_methods, i => i.Equals(invocationOperation.TargetMethod.Name)); | ||||
|                 if (methodName == null) | ||||
|                 { | ||||
|                     // if this operation isn't an invocation against one of the System.Console methods | ||||
|                     // defined in _methods then we can safely stop analyzing and return; | ||||
|                     var invocationOperation = (IInvocationOperation)context.Operation; | ||||
|                     return; | ||||
|                 } | ||||
|  | ||||
|                     var methodName = System.Array.Find(_methods, i => i.Equals(invocationOperation.TargetMethod.Name)); | ||||
|                     if (methodName == null) | ||||
|                     { | ||||
|                         return; | ||||
|                     } | ||||
|                 var systemConsoleType = context.Compilation.GetTypeByMetadataName("System.Console"); | ||||
|  | ||||
|                     var systemConsoleType = context.Compilation.GetTypeByMetadataName("System.Console"); | ||||
|                 if (!Equals(invocationOperation.TargetMethod.ContainingType, systemConsoleType)) | ||||
|                 { | ||||
|                     return; | ||||
|                 } | ||||
|  | ||||
|                     if (!Equals(invocationOperation.TargetMethod.ContainingType, systemConsoleType)) | ||||
|                     { | ||||
|                         return; | ||||
|                     } | ||||
|                 var methodSymbol = invocationOperation.TargetMethod; | ||||
|  | ||||
|                     var methodSymbol = invocationOperation.TargetMethod; | ||||
|                 var displayString = SymbolDisplay.ToDisplayString( | ||||
|                     methodSymbol, | ||||
|                     SymbolDisplayFormat.CSharpShortErrorMessageFormat | ||||
|                         .WithParameterOptions(SymbolDisplayParameterOptions.None) | ||||
|                         .WithGenericsOptions(SymbolDisplayGenericsOptions.None)); | ||||
|  | ||||
|                     var displayString = SymbolDisplay.ToDisplayString( | ||||
|                         methodSymbol, | ||||
|                         SymbolDisplayFormat.CSharpShortErrorMessageFormat | ||||
|                             .WithParameterOptions(SymbolDisplayParameterOptions.None) | ||||
|                             .WithGenericsOptions(SymbolDisplayGenericsOptions.None)); | ||||
|  | ||||
|                     context.ReportDiagnostic( | ||||
|                         Diagnostic.Create( | ||||
|                             _diagnosticDescriptor, | ||||
|                             invocationOperation.Syntax.GetLocation(), | ||||
|                             displayString)); | ||||
|                 }, OperationKind.Invocation); | ||||
|         } | ||||
|                 context.ReportDiagnostic( | ||||
|                     Diagnostic.Create( | ||||
|                         _diagnosticDescriptor, | ||||
|                         invocationOperation.Syntax.GetLocation(), | ||||
|                         displayString)); | ||||
|             }, OperationKind.Invocation); | ||||
|     } | ||||
| } | ||||
| } | ||||
|   | ||||
| @@ -1,15 +1,14 @@ | ||||
| namespace Spectre.Console.Analyzer | ||||
| { | ||||
|     internal static class Constants | ||||
|     { | ||||
|         internal const string StaticInstance = "AnsiConsole"; | ||||
|         internal const string SpectreConsole = "Spectre.Console"; | ||||
| namespace Spectre.Console.Analyzer; | ||||
|  | ||||
|         internal static readonly string[] LiveRenderables = | ||||
|         { | ||||
|             "Spectre.Console.LiveDisplay", | ||||
|             "Spectre.Console.Progress", | ||||
|             "Spectre.Console.Status", | ||||
|         }; | ||||
|     } | ||||
| } | ||||
| internal static class Constants | ||||
| { | ||||
|     internal const string StaticInstance = "AnsiConsole"; | ||||
|     internal const string SpectreConsole = "Spectre.Console"; | ||||
|  | ||||
|     internal static readonly string[] LiveRenderables = | ||||
|     { | ||||
|         "Spectre.Console.LiveDisplay", | ||||
|         "Spectre.Console.Progress", | ||||
|         "Spectre.Console.Status", | ||||
|     }; | ||||
| } | ||||
|   | ||||
| @@ -3,77 +3,76 @@ using Microsoft.CodeAnalysis; | ||||
| using static Microsoft.CodeAnalysis.DiagnosticSeverity; | ||||
| using static Spectre.Console.Analyzer.Descriptors.Category; | ||||
|  | ||||
| namespace Spectre.Console.Analyzer | ||||
| namespace Spectre.Console.Analyzer; | ||||
|  | ||||
| /// <summary> | ||||
| /// Code analysis descriptors. | ||||
| /// </summary> | ||||
| public static class Descriptors | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Code analysis descriptors. | ||||
|     /// </summary> | ||||
|     public static class Descriptors | ||||
|     internal enum Category | ||||
|     { | ||||
|         internal enum Category | ||||
|         { | ||||
|             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."); | ||||
|         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."); | ||||
| } | ||||
|   | ||||
| @@ -7,110 +7,109 @@ using Microsoft.CodeAnalysis.CSharp; | ||||
| using Microsoft.CodeAnalysis.CSharp.Syntax; | ||||
| using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; | ||||
|  | ||||
| namespace Spectre.Console.Analyzer.CodeActions | ||||
| namespace Spectre.Console.Analyzer.CodeActions; | ||||
|  | ||||
| /// <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> | ||||
|     /// Code action to change calls to System.Console to AnsiConsole. | ||||
|     /// Initializes a new instance of the <see cref="SwitchToAnsiConsoleAction"/> class. | ||||
|     /// </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; | ||||
|         private readonly InvocationExpressionSyntax _originalInvocation; | ||||
|  | ||||
|         /// <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; | ||||
|         } | ||||
|         _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; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -6,30 +6,29 @@ using Microsoft.CodeAnalysis.CodeFixes; | ||||
| using Microsoft.CodeAnalysis.CSharp.Syntax; | ||||
| using Spectre.Console.Analyzer.CodeActions; | ||||
|  | ||||
| namespace Spectre.Console.Analyzer.FixProviders | ||||
| namespace Spectre.Console.Analyzer.FixProviders; | ||||
|  | ||||
| /// <summary> | ||||
| /// Fix provider to change System.Console calls to AnsiConsole calls. | ||||
| /// </summary> | ||||
| [ExportCodeFixProvider(LanguageNames.CSharp)] | ||||
| [Shared] | ||||
| public class StaticAnsiConsoleToInstanceFix : CodeFixProvider | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Fix provider to change System.Console calls to AnsiConsole calls. | ||||
|     /// </summary> | ||||
|     [ExportCodeFixProvider(LanguageNames.CSharp)] | ||||
|     [Shared] | ||||
|     public class StaticAnsiConsoleToInstanceFix : CodeFixProvider | ||||
|     /// <inheritdoc /> | ||||
|     public sealed override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create( | ||||
|         Descriptors.S1010_FavorInstanceAnsiConsoleOverStatic.Id); | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public override async Task RegisterCodeFixesAsync(CodeFixContext context) | ||||
|     { | ||||
|         /// <inheritdoc /> | ||||
|         public sealed override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create( | ||||
|             Descriptors.S1010_FavorInstanceAnsiConsoleOverStatic.Id); | ||||
|  | ||||
|         /// <inheritdoc /> | ||||
|         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); | ||||
|         } | ||||
|         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 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> | ||||
|     /// Fix provider to change System.Console calls to AnsiConsole calls. | ||||
|     /// </summary> | ||||
|     [ExportCodeFixProvider(LanguageNames.CSharp)] | ||||
|     [Shared] | ||||
|     public class SystemConsoleToAnsiConsoleFix : CodeFixProvider | ||||
|     /// <inheritdoc /> | ||||
|     public sealed override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create( | ||||
|         Descriptors.S1000_UseAnsiConsoleOverSystemConsole.Id); | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; | ||||
|  | ||||
|     /// <inheritdoc /> | ||||
|     public override async Task RegisterCodeFixesAsync(CodeFixContext context) | ||||
|     { | ||||
|         /// <inheritdoc /> | ||||
|         public sealed override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create( | ||||
|             Descriptors.S1000_UseAnsiConsoleOverSystemConsole.Id); | ||||
|  | ||||
|         /// <inheritdoc /> | ||||
|         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); | ||||
|         } | ||||
|         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 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 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> | ||||
|     /// Represents a renderable image. | ||||
|     /// Gets the image width. | ||||
|     /// </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; | ||||
|  | ||||
|         /// <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); | ||||
|         } | ||||
|         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); | ||||
|     } | ||||
| } | ||||
| @@ -1,135 +1,134 @@ | ||||
| using System; | ||||
| using SixLabors.ImageSharp.Processing; | ||||
|  | ||||
| namespace Spectre.Console | ||||
| namespace Spectre.Console; | ||||
|  | ||||
| /// <summary> | ||||
| /// Contains extension methods for <see cref="CanvasImage"/>. | ||||
| /// </summary> | ||||
| public static class CanvasImageExtensions | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Contains extension methods for <see cref="CanvasImage"/>. | ||||
|     /// Sets the maximum width of the rendered image. | ||||
|     /// </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> | ||||
|         /// 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) | ||||
|         { | ||||
|             if (image is null) | ||||
|             { | ||||
|                 throw new ArgumentNullException(nameof(image)); | ||||
|             } | ||||
|  | ||||
|             image.MaxWidth = maxWidth; | ||||
|             return image; | ||||
|             throw new ArgumentNullException(nameof(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; | ||||
|         } | ||||
|         image.MaxWidth = maxWidth; | ||||
|         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 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> | ||||
|     /// A <see cref="ICommandInterceptor"/> that triggers a callback when invoked. | ||||
|     /// Initializes a new instance of the <see cref="CallbackCommandInterceptor"/> class. | ||||
|     /// </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> | ||||
|         /// Initializes a new instance of the <see cref="CallbackCommandInterceptor"/> class. | ||||
|         /// </summary> | ||||
|         /// <param name="callback">The callback to call when the interceptor is invoked.</param> | ||||
|         public CallbackCommandInterceptor(Action<CommandContext, CommandSettings> callback) | ||||
|         { | ||||
|             _callback = callback ?? throw new ArgumentNullException(nameof(callback)); | ||||
|         } | ||||
|  | ||||
|         /// <inheritdoc/> | ||||
|         public void Intercept(CommandContext context, CommandSettings settings) | ||||
|         { | ||||
|             _callback(context, settings); | ||||
|         } | ||||
|     /// <inheritdoc/> | ||||
|     public void Intercept(CommandContext context, CommandSettings settings) | ||||
|     { | ||||
|         _callback(context, settings); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,29 +1,28 @@ | ||||
| using System; | ||||
| 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> | ||||
|     /// Represents a <see cref="CommandApp"/> runtime failure. | ||||
|     /// Gets the exception that was thrown. | ||||
|     /// </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> | ||||
|         /// Gets the exception that was thrown. | ||||
|         /// </summary> | ||||
|         public Exception Exception { get; } | ||||
|  | ||||
|         /// <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(); | ||||
|         } | ||||
|         Exception = exception ?? throw new ArgumentNullException(nameof(exception)); | ||||
|         Output = output.NormalizeLineEndings() | ||||
|             .TrimLines() | ||||
|             .Trim(); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,43 +1,42 @@ | ||||
| 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> | ||||
|     /// Represents the result of a completed <see cref="CommandApp"/> run. | ||||
|     /// Gets the exit code. | ||||
|     /// </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> | ||||
|         /// Gets the exit code. | ||||
|         /// </summary> | ||||
|         public int ExitCode { get; } | ||||
|         ExitCode = exitCode; | ||||
|         Output = output ?? string.Empty; | ||||
|         Context = context; | ||||
|         Settings = settings; | ||||
|  | ||||
|         /// <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) | ||||
|         { | ||||
|             ExitCode = exitCode; | ||||
|             Output = output ?? string.Empty; | ||||
|             Context = context; | ||||
|             Settings = settings; | ||||
|  | ||||
|             Output = Output | ||||
|                 .NormalizeLineEndings() | ||||
|                 .TrimLines() | ||||
|                 .Trim(); | ||||
|         } | ||||
|         Output = Output | ||||
|             .NormalizeLineEndings() | ||||
|             .TrimLines() | ||||
|             .Trim(); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,135 +1,134 @@ | ||||
| using System; | ||||
| 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> | ||||
|     /// A <see cref="CommandApp"/> test harness. | ||||
|     /// Initializes a new instance of the <see cref="CommandAppTester"/> class. | ||||
|     /// </summary> | ||||
|     public sealed class CommandAppTester | ||||
|     /// <param name="registrar">The registrar.</param> | ||||
|     public CommandAppTester(ITypeRegistrar? registrar = null) | ||||
|     { | ||||
|         private Action<CommandApp>? _appConfiguration; | ||||
|         private Action<IConfigurator>? _configuration; | ||||
|         Registrar = registrar; | ||||
|     } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Initializes a new instance of the <see cref="CommandAppTester"/> class. | ||||
|         /// </summary> | ||||
|         /// <param name="registrar">The registrar.</param> | ||||
|         public CommandAppTester(ITypeRegistrar? registrar = null) | ||||
|     /// <summary> | ||||
|     /// Gets or sets the Registrar to use in the CommandApp. | ||||
|     /// </summary> | ||||
|     public ITypeRegistrar? Registrar { get; set; } | ||||
|  | ||||
|     /// <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> | ||||
|         /// Gets or sets the Registrar to use in the CommandApp. | ||||
|         /// </summary> | ||||
|         public ITypeRegistrar? Registrar { get; set; } | ||||
|         _configuration = action; | ||||
|     } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Sets the default command. | ||||
|         /// </summary> | ||||
|         /// <typeparam name="T">The default command type.</typeparam> | ||||
|         public void SetDefaultCommand<T>() | ||||
|             where T : class, ICommand | ||||
|     /// <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); | ||||
|  | ||||
|         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."); | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Configures the command application. | ||||
|         /// </summary> | ||||
|         /// <param name="action">The configuration action.</param> | ||||
|         public void Configure(Action<IConfigurator> action) | ||||
|         catch (T ex) | ||||
|         { | ||||
|             if (_configuration != null) | ||||
|             if (ex is CommandAppException commandAppException && commandAppException.Pretty != null) | ||||
|             { | ||||
|                 throw new InvalidOperationException("The command app harnest have already been configured."); | ||||
|                 console.Write(commandAppException.Pretty); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 console.WriteLine(ex.Message); | ||||
|             } | ||||
|  | ||||
|             _configuration = action; | ||||
|             return new CommandAppFailure(ex, console.Output); | ||||
|         } | ||||
|  | ||||
|         /// <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 | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             var console = new TestConsole().Width(int.MaxValue); | ||||
|  | ||||
|             try | ||||
|             { | ||||
|                 Run(args, console, c => c.PropagateExceptions()); | ||||
|                 throw new InvalidOperationException("Expected an exception to be thrown, but there was none."); | ||||
|             } | ||||
|             catch (T ex) | ||||
|             { | ||||
|                 if (ex is CommandAppException commandAppException && commandAppException.Pretty != null) | ||||
|                 { | ||||
|                     console.Write(commandAppException.Pretty); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     console.WriteLine(ex.Message); | ||||
|                 } | ||||
|  | ||||
|                 return new CommandAppFailure(ex, console.Output); | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             { | ||||
|                 throw new InvalidOperationException( | ||||
|                     $"Expected an exception of type '{typeof(T).FullName}' to be thrown, " | ||||
|                     + $"but received {ex.GetType().FullName}."); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         /// <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); | ||||
|             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); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,191 +1,190 @@ | ||||
| using System; | ||||
| 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> | ||||
|     /// This is a utility class for implementors of | ||||
|     /// <see cref="ITypeRegistrar"/> and corresponding <see cref="ITypeResolver"/>. | ||||
|     /// Initializes a new instance of the <see cref="TypeRegistrarBaseTests"/> class. | ||||
|     /// </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> | ||||
|         /// Initializes a new instance of the <see cref="TypeRegistrarBaseTests"/> class. | ||||
|         /// </summary> | ||||
|         /// <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) | ||||
|     /// <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>[] | ||||
|         { | ||||
|             _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, | ||||
|                 InstanceRegistrationsCanBeResolved, | ||||
|                 LazyRegistrationsCanBeResolved, | ||||
|                 ResolvingNotRegisteredServiceReturnsNull, | ||||
|                 ResolvingNullTypeReturnsNull, | ||||
|             }; | ||||
|         }; | ||||
|  | ||||
|             foreach (var test in testCases) | ||||
|             { | ||||
|                 test(_registrarFactory()); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         private static void ResolvingNullTypeReturnsNull(ITypeRegistrar registrar) | ||||
|         foreach (var test in testCases) | ||||
|         { | ||||
|             // Given no registration | ||||
|             var resolver = registrar.Build(); | ||||
|  | ||||
|             try | ||||
|             { | ||||
|                 // When | ||||
|                 var actual = resolver.Resolve(null); | ||||
|  | ||||
|                 // Then | ||||
|                 if (actual != null) | ||||
|                 { | ||||
|                     throw new TestFailedException( | ||||
|                         $"Expected the resolver to resolve null, since null was requested as the service type. Actually resolved {actual.GetType().Name}."); | ||||
|                 } | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             { | ||||
|                 throw new TestFailedException( | ||||
|                     $"Expected the resolver not to throw, but caught {ex.GetType().Name}.", ex); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         private static void ResolvingNotRegisteredServiceReturnsNull(ITypeRegistrar registrar) | ||||
|         { | ||||
|             // Given no registration | ||||
|             var resolver = registrar.Build(); | ||||
|  | ||||
|             try | ||||
|             { | ||||
|                 // When | ||||
|                 var actual = resolver.Resolve(typeof(IMockService)); | ||||
|  | ||||
|                 // Then | ||||
|                 if (actual != null) | ||||
|                 { | ||||
|                     throw new TestFailedException( | ||||
|                         $"Expected the resolver to resolve null, since no service was registered. Actually resolved {actual.GetType().Name}."); | ||||
|                 } | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             { | ||||
|                 throw new TestFailedException( | ||||
|                     $"Expected the resolver not to throw, but caught {ex.GetType().Name}.", ex); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         private static void RegistrationsCanBeResolved(ITypeRegistrar registrar) | ||||
|         { | ||||
|             // Given | ||||
|             registrar.Register(typeof(IMockService), typeof(MockService)); | ||||
|             var resolver = registrar.Build(); | ||||
|  | ||||
|             // When | ||||
|             var actual = resolver.Resolve(typeof(IMockService)); | ||||
|  | ||||
|             // Then | ||||
|             if (actual == null) | ||||
|             { | ||||
|                 throw new TestFailedException( | ||||
|                     $"Expected the resolver to resolve an instance of {nameof(MockService)}. Actually resolved null."); | ||||
|             } | ||||
|  | ||||
|             if (actual is not MockService) | ||||
|             { | ||||
|                 throw new TestFailedException( | ||||
|                     $"Expected the resolver to resolve an instance of {nameof(MockService)}. Actually resolved {actual.GetType().Name}."); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         private static void InstanceRegistrationsCanBeResolved(ITypeRegistrar registrar) | ||||
|         { | ||||
|             // Given | ||||
|             var instance = new MockService(); | ||||
|             registrar.RegisterInstance(typeof(IMockService), instance); | ||||
|             var resolver = registrar.Build(); | ||||
|  | ||||
|             // When | ||||
|             var actual = resolver.Resolve(typeof(IMockService)); | ||||
|  | ||||
|             // Then | ||||
|             if (!ReferenceEquals(actual, instance)) | ||||
|             { | ||||
|                 throw new TestFailedException( | ||||
|                     "Expected the resolver to resolve exactly the registered instance."); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         private static void LazyRegistrationsCanBeResolved(ITypeRegistrar registrar) | ||||
|         { | ||||
|             // Given | ||||
|             var instance = new MockService(); | ||||
|             var factoryCalled = false; | ||||
|             registrar.RegisterLazy(typeof(IMockService), () => | ||||
|             { | ||||
|                 factoryCalled = true; | ||||
|                 return instance; | ||||
|             }); | ||||
|             var resolver = registrar.Build(); | ||||
|  | ||||
|             // When | ||||
|             var actual = resolver.Resolve(typeof(IMockService)); | ||||
|  | ||||
|             // Then | ||||
|             if (!factoryCalled) | ||||
|             { | ||||
|                 throw new TestFailedException( | ||||
|                     "Expected the factory to be called, to resolve the lazy registration."); | ||||
|             } | ||||
|  | ||||
|             if (!ReferenceEquals(actual, instance)) | ||||
|             { | ||||
|                 throw new TestFailedException( | ||||
|                     "Expected the resolver to return exactly the result of the lazy-registered factory."); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         /// <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) | ||||
|             { | ||||
|             } | ||||
|             test(_registrarFactory()); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
|     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; | ||||
|  | ||||
| namespace Spectre.Console.Testing | ||||
| namespace Spectre.Console.Testing; | ||||
|  | ||||
| /// <summary> | ||||
| /// Contains extensions for <see cref="string"/>. | ||||
| /// </summary> | ||||
| public static class StringExtensions | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Contains extensions for <see cref="string"/>. | ||||
|     /// Returns a new string with all lines trimmed of trailing whitespace. | ||||
|     /// </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> | ||||
|         /// 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) | ||||
|         { | ||||
|             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; | ||||
|         } | ||||
|  | ||||
|         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> | ||||
|     /// Contains extensions for <see cref="Style"/>. | ||||
|     /// Sets the foreground or background color of the specified style. | ||||
|     /// </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> | ||||
|         /// 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) | ||||
|         { | ||||
|             if (foreground) | ||||
|             { | ||||
|                 return style.Foreground(color); | ||||
|             } | ||||
|  | ||||
|             return style.Background(color); | ||||
|             return style.Foreground(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.Threading.Tasks; | ||||
|  | ||||
| namespace Spectre.Console.Testing | ||||
| { | ||||
|     internal sealed class NoopExclusivityMode : IExclusivityMode | ||||
|     { | ||||
|         public T Run<T>(Func<T> func) | ||||
|         { | ||||
|             return func(); | ||||
|         } | ||||
| namespace Spectre.Console.Testing; | ||||
|  | ||||
|         public async Task<T> RunAsync<T>(Func<Task<T>> func) | ||||
|         { | ||||
|             return await func().ConfigureAwait(false); | ||||
|         } | ||||
| internal sealed class NoopExclusivityMode : IExclusivityMode | ||||
| { | ||||
|     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; | ||||
|  | ||||
| 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> | ||||
|     /// Represents fake capabilities useful in tests. | ||||
|     /// Creates a <see cref="RenderContext"/> with the same capabilities as this instace. | ||||
|     /// </summary> | ||||
|     public sealed class TestCapabilities : IReadOnlyCapabilities | ||||
|     /// <returns>A <see cref="RenderContext"/> with the same capabilities as this instace.</returns> | ||||
|     public RenderContext CreateRenderContext() | ||||
|     { | ||||
|         /// <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> | ||||
|         /// 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); | ||||
|         } | ||||
|         return new RenderContext(this); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -3,120 +3,119 @@ using System.Collections.Generic; | ||||
| using System.IO; | ||||
| 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> | ||||
|     /// A testable console. | ||||
|     /// Gets the console input. | ||||
|     /// </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; | ||||
|         private readonly StringWriter _writer; | ||||
|         private IAnsiConsoleCursor? _cursor; | ||||
|         _writer = new StringWriter(); | ||||
|         _cursor = new NoopCursor(); | ||||
|  | ||||
|         /// <inheritdoc/> | ||||
|         public Profile Profile => _console.Profile; | ||||
|         Input = new TestConsoleInput(); | ||||
|         EmitAnsiSequences = false; | ||||
|  | ||||
|         /// <inheritdoc/> | ||||
|         public IExclusivityMode ExclusivityMode => _console.ExclusivityMode; | ||||
|  | ||||
|         /// <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() | ||||
|         var factory = new AnsiConsoleFactory(); | ||||
|         _console = factory.Create(new AnsiConsoleSettings | ||||
|         { | ||||
|             _writer = new StringWriter(); | ||||
|             _cursor = new NoopCursor(); | ||||
|  | ||||
|             Input = new TestConsoleInput(); | ||||
|             EmitAnsiSequences = false; | ||||
|  | ||||
|             var factory = new AnsiConsoleFactory(); | ||||
|             _console = factory.Create(new AnsiConsoleSettings | ||||
|             Ansi = AnsiSupport.Yes, | ||||
|             ColorSystem = (ColorSystemSupport)ColorSystem.TrueColor, | ||||
|             Out = new AnsiConsoleOutput(_writer), | ||||
|             Interactive = InteractionSupport.No, | ||||
|             ExclusivityMode = new NoopExclusivityMode(), | ||||
|             Enrichment = new ProfileEnrichment | ||||
|             { | ||||
|                 Ansi = AnsiSupport.Yes, | ||||
|                 ColorSystem = (ColorSystemSupport)ColorSystem.TrueColor, | ||||
|                 Out = new AnsiConsoleOutput(_writer), | ||||
|                 Interactive = InteractionSupport.No, | ||||
|                 ExclusivityMode = new NoopExclusivityMode(), | ||||
|                 Enrichment = new ProfileEnrichment | ||||
|                 UseDefaultEnrichers = false, | ||||
|             }, | ||||
|         }); | ||||
|  | ||||
|         _console.Profile.Width = 80; | ||||
|         _console.Profile.Height = 24; | ||||
|         _console.Profile.Capabilities.Ansi = true; | ||||
|         _console.Profile.Capabilities.Unicode = true; | ||||
|     } | ||||
|  | ||||
|     /// <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, | ||||
|                 }, | ||||
|             }); | ||||
|  | ||||
|             _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); | ||||
|                     continue; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         internal void SetCursor(IAnsiConsoleCursor? cursor) | ||||
|         { | ||||
|             _cursor = cursor; | ||||
|                 Profile.Out.Writer.Write(segment.Text); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     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> | ||||
|     /// Contains extensions for <see cref="TestConsole"/>. | ||||
|     /// Sets the console's color system. | ||||
|     /// </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> | ||||
|         /// Sets the console's color system. | ||||
|         /// </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; | ||||
|         } | ||||
|         console.Profile.Capabilities.ColorSystem = colors; | ||||
|         return console; | ||||
|     } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Sets whether or not ANSI is supported. | ||||
|         /// </summary> | ||||
|         /// <param name="console">The console.</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> | ||||
|         public static TestConsole SupportsAnsi(this TestConsole console, bool enable) | ||||
|         { | ||||
|             console.Profile.Capabilities.Ansi = enable; | ||||
|             return console; | ||||
|         } | ||||
|     /// <summary> | ||||
|     /// Sets whether or not ANSI is supported. | ||||
|     /// </summary> | ||||
|     /// <param name="console">The console.</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> | ||||
|     public static TestConsole SupportsAnsi(this TestConsole console, bool enable) | ||||
|     { | ||||
|         console.Profile.Capabilities.Ansi = enable; | ||||
|         return console; | ||||
|     } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Makes the console interactive. | ||||
|         /// </summary> | ||||
|         /// <param name="console">The console.</param> | ||||
|         /// <returns>The same instance so that multiple calls can be chained.</returns> | ||||
|         public static TestConsole Interactive(this TestConsole console) | ||||
|         { | ||||
|             console.Profile.Capabilities.Interactive = true; | ||||
|             return console; | ||||
|         } | ||||
|     /// <summary> | ||||
|     /// Makes the console interactive. | ||||
|     /// </summary> | ||||
|     /// <param name="console">The console.</param> | ||||
|     /// <returns>The same instance so that multiple calls can be chained.</returns> | ||||
|     public static TestConsole Interactive(this TestConsole console) | ||||
|     { | ||||
|         console.Profile.Capabilities.Interactive = true; | ||||
|         return console; | ||||
|     } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Sets the console width. | ||||
|         /// </summary> | ||||
|         /// <param name="console">The console.</param> | ||||
|         /// <param name="width">The console width.</param> | ||||
|         /// <returns>The same instance so that multiple calls can be chained.</returns> | ||||
|         public static TestConsole Width(this TestConsole console, int width) | ||||
|         { | ||||
|             console.Profile.Width = width; | ||||
|             return console; | ||||
|         } | ||||
|     /// <summary> | ||||
|     /// Sets the console width. | ||||
|     /// </summary> | ||||
|     /// <param name="console">The console.</param> | ||||
|     /// <param name="width">The console width.</param> | ||||
|     /// <returns>The same instance so that multiple calls can be chained.</returns> | ||||
|     public static TestConsole Width(this TestConsole console, int width) | ||||
|     { | ||||
|         console.Profile.Width = width; | ||||
|         return console; | ||||
|     } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Turns on emitting of VT/ANSI sequences. | ||||
|         /// </summary> | ||||
|         /// <param name="console">The console.</param> | ||||
|         /// <returns>The same instance so that multiple calls can be chained.</returns> | ||||
|         public static TestConsole EmitAnsiSequences(this TestConsole console) | ||||
|         { | ||||
|             console.SetCursor(null); | ||||
|             console.EmitAnsiSequences = true; | ||||
|             return console; | ||||
|         } | ||||
|     /// <summary> | ||||
|     /// Turns on emitting of VT/ANSI sequences. | ||||
|     /// </summary> | ||||
|     /// <param name="console">The console.</param> | ||||
|     /// <returns>The same instance so that multiple calls can be chained.</returns> | ||||
|     public static TestConsole EmitAnsiSequences(this TestConsole console) | ||||
|     { | ||||
|         console.SetCursor(null); | ||||
|         console.EmitAnsiSequences = true; | ||||
|         return console; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -3,90 +3,89 @@ using System.Collections.Generic; | ||||
| using System.Threading; | ||||
| 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> | ||||
|     /// Represents a testable console input mechanism. | ||||
|     /// Initializes a new instance of the <see cref="TestConsoleInput"/> class. | ||||
|     /// </summary> | ||||
|     public sealed class TestConsoleInput : IAnsiConsoleInput | ||||
|     public TestConsoleInput() | ||||
|     { | ||||
|         private readonly Queue<ConsoleKeyInfo> _input; | ||||
|         _input = new Queue<ConsoleKeyInfo>(); | ||||
|     } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Initializes a new instance of the <see cref="TestConsoleInput"/> class. | ||||
|         /// </summary> | ||||
|         public TestConsoleInput() | ||||
|     /// <summary> | ||||
|     /// 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) | ||||
|         { | ||||
|             _input = new Queue<ConsoleKeyInfo>(); | ||||
|             throw new ArgumentNullException(nameof(input)); | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Pushes the specified text to the input queue. | ||||
|         /// </summary> | ||||
|         /// <param name="input">The input string.</param> | ||||
|         public void PushText(string input) | ||||
|         foreach (var character in input) | ||||
|         { | ||||
|             if (input is null) | ||||
|             { | ||||
|                 throw new ArgumentNullException(nameof(input)); | ||||
|             } | ||||
|  | ||||
|             foreach (var character in input) | ||||
|             { | ||||
|                 PushCharacter(character); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         /// <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)); | ||||
|             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)); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,30 +1,29 @@ | ||||
| using System; | ||||
|  | ||||
| namespace Spectre.Console | ||||
| namespace Spectre.Console; | ||||
|  | ||||
| /// <summary> | ||||
| /// A console capable of writing ANSI escape sequences. | ||||
| /// </summary> | ||||
| public static partial class AnsiConsole | ||||
| { | ||||
|     /// <summary> | ||||
|     /// A console capable of writing ANSI escape sequences. | ||||
|     /// Writes an exception to the console. | ||||
|     /// </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> | ||||
|         /// 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); | ||||
|         } | ||||
|         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); | ||||
|     } | ||||
| } | ||||
| @@ -1,20 +1,19 @@ | ||||
| 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> | ||||
|     /// A console capable of writing ANSI escape sequences. | ||||
|     /// Creates a new <see cref="LiveDisplay"/> instance. | ||||
|     /// </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> | ||||
|         /// 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); | ||||
|         } | ||||
|         return Console.Live(target); | ||||
|     } | ||||
| } | ||||
| } | ||||
| @@ -1,70 +1,69 @@ | ||||
| using System; | ||||
|  | ||||
| namespace Spectre.Console | ||||
| namespace Spectre.Console; | ||||
|  | ||||
| /// <summary> | ||||
| /// A console capable of writing ANSI escape sequences. | ||||
| /// </summary> | ||||
| public static partial class AnsiConsole | ||||
| { | ||||
|     /// <summary> | ||||
|     /// A console capable of writing ANSI escape sequences. | ||||
|     /// Writes the specified markup to the console. | ||||
|     /// </summary> | ||||
|     public static partial class AnsiConsole | ||||
|     /// <param name="value">The value to write.</param> | ||||
|     public static void Markup(string value) | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// 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); | ||||
|         } | ||||
|         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); | ||||
|     } | ||||
| } | ||||
| @@ -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> | ||||
|     /// A console capable of writing ANSI escape sequences. | ||||
|     /// Creates a new <see cref="Progress"/> instance. | ||||
|     /// </summary> | ||||
|     public static partial class AnsiConsole | ||||
|     /// <returns>A <see cref="Progress"/> instance.</returns> | ||||
|     public static Progress Progress() | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// 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(); | ||||
|         } | ||||
|         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(); | ||||
|     } | ||||
| } | ||||
| @@ -1,66 +1,65 @@ | ||||
| using System; | ||||
|  | ||||
| namespace Spectre.Console | ||||
| namespace Spectre.Console; | ||||
|  | ||||
| /// <summary> | ||||
| /// A console capable of writing ANSI escape sequences. | ||||
| /// </summary> | ||||
| public static partial class AnsiConsole | ||||
| { | ||||
|     /// <summary> | ||||
|     /// A console capable of writing ANSI escape sequences. | ||||
|     /// Displays a prompt to the user. | ||||
|     /// </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> | ||||
|         /// 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) | ||||
|         { | ||||
|             if (prompt is null) | ||||
|             { | ||||
|                 throw new ArgumentNullException(nameof(prompt)); | ||||
|             } | ||||
|  | ||||
|             return prompt.Show(Console); | ||||
|             throw new ArgumentNullException(nameof(prompt)); | ||||
|         } | ||||
|  | ||||
|         /// <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); | ||||
|         } | ||||
|         return prompt.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 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> | ||||
|     /// A console capable of writing ANSI escape sequences. | ||||
|     /// Starts recording the console output. | ||||
|     /// </summary> | ||||
|     public static partial class AnsiConsole | ||||
|     public static void Record() | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Starts recording the console output. | ||||
|         /// </summary> | ||||
|         public static void Record() | ||||
|         if (_recorder == null) | ||||
|         { | ||||
|             if (_recorder == null) | ||||
|             { | ||||
|                 _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); | ||||
|             _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); | ||||
|     } | ||||
| } | ||||
| @@ -1,35 +1,34 @@ | ||||
| using System; | ||||
| 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> | ||||
|     /// A console capable of writing ANSI escape sequences. | ||||
|     /// Renders the specified object to the console. | ||||
|     /// </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> | ||||
|         /// 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); | ||||
|         } | ||||
|         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; | ||||
|  | ||||
| namespace Spectre.Console | ||||
| namespace Spectre.Console; | ||||
|  | ||||
| /// <summary> | ||||
| /// A console capable of writing ANSI escape sequences. | ||||
| /// </summary> | ||||
| public static partial class AnsiConsole | ||||
| { | ||||
|     /// <summary> | ||||
|     /// A console capable of writing ANSI escape sequences. | ||||
|     /// Switches to an alternate screen buffer if the terminal supports it. | ||||
|     /// </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> | ||||
|         /// 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); | ||||
|         } | ||||
|         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> | ||||
|     /// A console capable of writing ANSI escape sequences. | ||||
|     /// Gets or sets the foreground color. | ||||
|     /// </summary> | ||||
|     public static partial class AnsiConsole | ||||
|     public static Color Foreground | ||||
|     { | ||||
|         internal static Style CurrentStyle { get; private set; } = Style.Plain; | ||||
|         internal static bool Created { get; private set; } | ||||
|  | ||||
|         /// <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; | ||||
|         } | ||||
|         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; | ||||
|     } | ||||
| } | ||||
| @@ -1,253 +1,252 @@ | ||||
| using System; | ||||
| 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> | ||||
|     /// A console capable of writing ANSI escape sequences. | ||||
|     /// Writes the specified string value to the console. | ||||
|     /// </summary> | ||||
|     public static partial class AnsiConsole | ||||
|     /// <param name="value">The value to write.</param> | ||||
|     public static void Write(string value) | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Writes the specified string value to the console. | ||||
|         /// </summary> | ||||
|         /// <param name="value">The value to write.</param> | ||||
|         public static void Write(string value) | ||||
|         Write(value, CurrentStyle); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// 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> | ||||
|         /// 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) | ||||
|         for (var index = 0; index < value.Length; index++) | ||||
|         { | ||||
|             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) | ||||
|             { | ||||
|                 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); | ||||
|             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); | ||||
|     } | ||||
| } | ||||
| @@ -1,273 +1,272 @@ | ||||
| using System; | ||||
| 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> | ||||
|     /// A console capable of writing ANSI escape sequences. | ||||
|     /// Writes an empty line to the console. | ||||
|     /// </summary> | ||||
|     public static partial class AnsiConsole | ||||
|     public static void WriteLine() | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// 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); | ||||
|         } | ||||
|         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); | ||||
|     } | ||||
| } | ||||
| @@ -1,78 +1,77 @@ | ||||
| using System; | ||||
|  | ||||
| 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), | ||||
|                 }); | ||||
| namespace Spectre.Console; | ||||
|  | ||||
|                 Created = true; | ||||
|                 return 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), | ||||
|             }); | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets or sets the underlying <see cref="IAnsiConsole"/>. | ||||
|         /// </summary> | ||||
|         public static IAnsiConsole Console | ||||
|             Created = true; | ||||
|             return console; | ||||
|         }); | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Gets or sets the underlying <see cref="IAnsiConsole"/>. | ||||
|     /// </summary> | ||||
|     public static IAnsiConsole Console | ||||
|     { | ||||
|         get | ||||
|         { | ||||
|             get | ||||
|             { | ||||
|                 return _recorder ?? _console.Value; | ||||
|             } | ||||
|             set | ||||
|             { | ||||
|                 _console = new Lazy<IAnsiConsole>(() => value); | ||||
|  | ||||
|                 if (_recorder != null) | ||||
|                 { | ||||
|                     // Recreate the recorder | ||||
|                     _recorder = _recorder.Clone(value); | ||||
|                 } | ||||
|  | ||||
|                 Created = true; | ||||
|             } | ||||
|             return _recorder ?? _console.Value; | ||||
|         } | ||||
|  | ||||
|         /// <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) | ||||
|         set | ||||
|         { | ||||
|             var factory = new AnsiConsoleFactory(); | ||||
|             return factory.Create(settings); | ||||
|         } | ||||
|             _console = new Lazy<IAnsiConsole>(() => value); | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Clears the console. | ||||
|         /// </summary> | ||||
|         public static void Clear() | ||||
|         { | ||||
|             Console.Clear(); | ||||
|             if (_recorder != null) | ||||
|             { | ||||
|                 // Recreate the recorder | ||||
|                 _recorder = _recorder.Clone(value); | ||||
|             } | ||||
|  | ||||
|             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.Internal; | ||||
|  | ||||
| namespace Spectre.Console | ||||
| namespace Spectre.Console; | ||||
|  | ||||
| /// <summary> | ||||
| /// Factory for creating an ANSI console. | ||||
| /// </summary> | ||||
| public sealed class AnsiConsoleFactory | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Factory for creating an ANSI console. | ||||
|     /// Creates an ANSI console. | ||||
|     /// </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> | ||||
|         /// 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) | ||||
|         { | ||||
|             if (settings is null) | ||||
|             { | ||||
|                 throw new ArgumentNullException(nameof(settings)); | ||||
|             } | ||||
|  | ||||
|             var output = settings.Out ?? new AnsiConsoleOutput(System.Console.Out); | ||||
|             if (output.Writer == null) | ||||
|             { | ||||
|                 throw new InvalidOperationException("Output writer was null"); | ||||
|             } | ||||
|  | ||||
|             // Detect if the terminal support ANSI or not | ||||
|             var (supportsAnsi, legacyConsole) = DetectAnsi(settings, output.Writer); | ||||
|  | ||||
|             // Use console encoding or fall back to provided encoding | ||||
|             var encoding = output.Writer.IsStandardOut() || output.Writer.IsStandardError() | ||||
|                 ? System.Console.OutputEncoding : output.Writer.Encoding; | ||||
|  | ||||
|             // Get the color system | ||||
|             var colorSystem = settings.ColorSystem == ColorSystemSupport.Detect | ||||
|                 ? ColorSystemDetector.Detect(supportsAnsi) | ||||
|                 : (ColorSystem)settings.ColorSystem; | ||||
|  | ||||
|             // Get whether or not we consider the terminal interactive | ||||
|             var interactive = settings.Interactive == InteractionSupport.Yes; | ||||
|             if (settings.Interactive == InteractionSupport.Detect) | ||||
|             { | ||||
|                 interactive = Environment.UserInteractive; | ||||
|             } | ||||
|  | ||||
|             var profile = new Profile(output, encoding); | ||||
|  | ||||
|             profile.Capabilities.ColorSystem = colorSystem; | ||||
|             profile.Capabilities.Ansi = supportsAnsi; | ||||
|             profile.Capabilities.Links = supportsAnsi && !legacyConsole; | ||||
|             profile.Capabilities.Legacy = legacyConsole; | ||||
|             profile.Capabilities.Interactive = interactive; | ||||
|             profile.Capabilities.Unicode = encoding.EncodingName.ContainsExact("Unicode"); | ||||
|             profile.Capabilities.AlternateBuffer = supportsAnsi && !legacyConsole; | ||||
|  | ||||
|             // Enrich the profile | ||||
|             ProfileEnricher.Enrich( | ||||
|                 profile, | ||||
|                 settings.Enrichment, | ||||
|                 settings.EnvironmentVariables); | ||||
|  | ||||
|             return new AnsiConsoleFacade( | ||||
|                 profile, | ||||
|                 settings.ExclusivityMode ?? new DefaultExclusivityMode()); | ||||
|             throw new ArgumentNullException(nameof(settings)); | ||||
|         } | ||||
|  | ||||
|         private static (bool Ansi, bool Legacy) DetectAnsi(AnsiConsoleSettings settings, System.IO.TextWriter buffer) | ||||
|         var output = settings.Out ?? new AnsiConsoleOutput(System.Console.Out); | ||||
|         if (output.Writer == null) | ||||
|         { | ||||
|             var supportsAnsi = settings.Ansi == AnsiSupport.Yes; | ||||
|             var legacyConsole = false; | ||||
|             throw new InvalidOperationException("Output writer was null"); | ||||
|         } | ||||
|  | ||||
|             if (settings.Ansi == AnsiSupport.Detect) | ||||
|         // Detect if the terminal support ANSI or not | ||||
|         var (supportsAnsi, legacyConsole) = DetectAnsi(settings, output.Writer); | ||||
|  | ||||
|         // Use console encoding or fall back to provided encoding | ||||
|         var encoding = output.Writer.IsStandardOut() || output.Writer.IsStandardError() | ||||
|             ? System.Console.OutputEncoding : output.Writer.Encoding; | ||||
|  | ||||
|         // Get the color system | ||||
|         var colorSystem = settings.ColorSystem == ColorSystemSupport.Detect | ||||
|             ? ColorSystemDetector.Detect(supportsAnsi) | ||||
|             : (ColorSystem)settings.ColorSystem; | ||||
|  | ||||
|         // Get whether or not we consider the terminal interactive | ||||
|         var interactive = settings.Interactive == InteractionSupport.Yes; | ||||
|         if (settings.Interactive == InteractionSupport.Detect) | ||||
|         { | ||||
|             interactive = Environment.UserInteractive; | ||||
|         } | ||||
|  | ||||
|         var profile = new Profile(output, encoding); | ||||
|  | ||||
|         profile.Capabilities.ColorSystem = colorSystem; | ||||
|         profile.Capabilities.Ansi = supportsAnsi; | ||||
|         profile.Capabilities.Links = supportsAnsi && !legacyConsole; | ||||
|         profile.Capabilities.Legacy = legacyConsole; | ||||
|         profile.Capabilities.Interactive = interactive; | ||||
|         profile.Capabilities.Unicode = encoding.EncodingName.ContainsExact("Unicode"); | ||||
|         profile.Capabilities.AlternateBuffer = supportsAnsi && !legacyConsole; | ||||
|  | ||||
|         // Enrich the profile | ||||
|         ProfileEnricher.Enrich( | ||||
|             profile, | ||||
|             settings.Enrichment, | ||||
|             settings.EnvironmentVariables); | ||||
|  | ||||
|         return new AnsiConsoleFacade( | ||||
|             profile, | ||||
|             settings.ExclusivityMode ?? new DefaultExclusivityMode()); | ||||
|     } | ||||
|  | ||||
|     private static (bool Ansi, bool Legacy) DetectAnsi(AnsiConsoleSettings settings, System.IO.TextWriter buffer) | ||||
|     { | ||||
|         var supportsAnsi = settings.Ansi == AnsiSupport.Yes; | ||||
|         var legacyConsole = false; | ||||
|  | ||||
|         if (settings.Ansi == AnsiSupport.Detect) | ||||
|         { | ||||
|             (supportsAnsi, legacyConsole) = AnsiDetector.Detect(buffer.IsStandardError(), true); | ||||
|  | ||||
|             // Check whether or not this is a legacy console from the existing instance (if any). | ||||
|             // We need to do this because once we upgrade the console to support ENABLE_VIRTUAL_TERMINAL_PROCESSING | ||||
|             // on Windows, there is no way of detecting whether or not we're running on a legacy console or not. | ||||
|             if (AnsiConsole.Created && !legacyConsole && (buffer.IsStandardOut() || buffer.IsStandardError()) && AnsiConsole.Profile.Capabilities.Legacy) | ||||
|             { | ||||
|                 (supportsAnsi, legacyConsole) = AnsiDetector.Detect(buffer.IsStandardError(), true); | ||||
|  | ||||
|                 // Check whether or not this is a legacy console from the existing instance (if any). | ||||
|                 // We need to do this because once we upgrade the console to support ENABLE_VIRTUAL_TERMINAL_PROCESSING | ||||
|                 // on Windows, there is no way of detecting whether or not we're running on a legacy console or not. | ||||
|                 if (AnsiConsole.Created && !legacyConsole && (buffer.IsStandardOut() || buffer.IsStandardError()) && AnsiConsole.Profile.Capabilities.Legacy) | ||||
|                 { | ||||
|                     legacyConsole = AnsiConsole.Profile.Capabilities.Legacy; | ||||
|                 } | ||||
|                 legacyConsole = AnsiConsole.Profile.Capabilities.Legacy; | ||||
|             } | ||||
|             else | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             if (buffer.IsStandardOut() || buffer.IsStandardError()) | ||||
|             { | ||||
|                 if (buffer.IsStandardOut() || buffer.IsStandardError()) | ||||
|                 // Are we running on Windows? | ||||
|                 if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) | ||||
|                 { | ||||
|                     // Are we running on Windows? | ||||
|                     if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) | ||||
|                     // Not the first console we're creating? | ||||
|                     if (AnsiConsole.Created) | ||||
|                     { | ||||
|                         // Not the first console we're creating? | ||||
|                         if (AnsiConsole.Created) | ||||
|                         { | ||||
|                             legacyConsole = AnsiConsole.Profile.Capabilities.Legacy; | ||||
|                         } | ||||
|                         else | ||||
|                         { | ||||
|                             // Try detecting whether or not this is a legacy console | ||||
|                             (_, legacyConsole) = AnsiDetector.Detect(buffer.IsStandardError(), false); | ||||
|                         } | ||||
|                         legacyConsole = AnsiConsole.Profile.Capabilities.Legacy; | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         // Try detecting whether or not this is a legacy console | ||||
|                         (_, legacyConsole) = AnsiDetector.Detect(buffer.IsStandardError(), false); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             return (supportsAnsi, legacyConsole); | ||||
|         } | ||||
|  | ||||
|         return (supportsAnsi, legacyConsole); | ||||
|     } | ||||
| } | ||||
| } | ||||
| @@ -2,57 +2,56 @@ using System; | ||||
| using System.IO; | ||||
| using System.Text; | ||||
|  | ||||
| namespace Spectre.Console | ||||
| namespace Spectre.Console; | ||||
|  | ||||
| /// <summary> | ||||
| /// Represents console output. | ||||
| /// </summary> | ||||
| public sealed class AnsiConsoleOutput : IAnsiConsoleOutput | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Represents console output. | ||||
|     /// </summary> | ||||
|     public sealed class AnsiConsoleOutput : IAnsiConsoleOutput | ||||
|     /// <inheritdoc/> | ||||
|     public TextWriter Writer { get; } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public bool IsTerminal | ||||
|     { | ||||
|         /// <inheritdoc/> | ||||
|         public TextWriter Writer { get; } | ||||
|  | ||||
|         /// <inheritdoc/> | ||||
|         public bool IsTerminal | ||||
|         get | ||||
|         { | ||||
|             get | ||||
|             if (Writer.IsStandardOut()) | ||||
|             { | ||||
|                 if (Writer.IsStandardOut()) | ||||
|                 { | ||||
|                     return !System.Console.IsOutputRedirected; | ||||
|                 } | ||||
|  | ||||
|                 if (Writer.IsStandardError()) | ||||
|                 { | ||||
|                     return !System.Console.IsErrorRedirected; | ||||
|                 } | ||||
|  | ||||
|                 return false; | ||||
|                 return !System.Console.IsOutputRedirected; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         /// <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()) | ||||
|             if (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; | ||||
|  | ||||
| namespace Spectre.Console | ||||
| namespace Spectre.Console; | ||||
|  | ||||
| /// <summary> | ||||
| /// Settings used when building a <see cref="IAnsiConsole"/>. | ||||
| /// </summary> | ||||
| public sealed class AnsiConsoleSettings | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Settings used when building a <see cref="IAnsiConsole"/>. | ||||
|     /// Gets or sets a value indicating whether or | ||||
|     /// not ANSI escape sequences are supported. | ||||
|     /// </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> | ||||
|         /// 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(); | ||||
|         } | ||||
|         Enrichment = new ProfileEnrichment(); | ||||
|     } | ||||
| } | ||||
| } | ||||
| @@ -1,24 +1,23 @@ | ||||
| namespace Spectre.Console | ||||
| namespace Spectre.Console; | ||||
|  | ||||
| /// <summary> | ||||
| /// Determines ANSI escape sequence support. | ||||
| /// </summary> | ||||
| public enum AnsiSupport | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Determines ANSI escape sequence support. | ||||
|     /// ANSI escape sequence support should | ||||
|     /// be detected by the system. | ||||
|     /// </summary> | ||||
|     public enum AnsiSupport | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// ANSI escape sequence support should | ||||
|         /// be detected by the system. | ||||
|         /// </summary> | ||||
|         Detect = 0, | ||||
|     Detect = 0, | ||||
|  | ||||
|         /// <summary> | ||||
|         /// ANSI escape sequences are supported. | ||||
|         /// </summary> | ||||
|         Yes = 1, | ||||
|     /// <summary> | ||||
|     /// ANSI escape sequences are supported. | ||||
|     /// </summary> | ||||
|     Yes = 1, | ||||
|  | ||||
|         /// <summary> | ||||
|         /// ANSI escape sequences are not supported. | ||||
|         /// </summary> | ||||
|         No = 2, | ||||
|     } | ||||
| } | ||||
|     /// <summary> | ||||
|     /// ANSI escape sequences are not supported. | ||||
|     /// </summary> | ||||
|     No = 2, | ||||
| } | ||||
| @@ -1,42 +1,41 @@ | ||||
| using System.Diagnostics.CodeAnalysis; | ||||
| using Spectre.Console.Rendering; | ||||
|  | ||||
| namespace Spectre.Console | ||||
| namespace Spectre.Console; | ||||
|  | ||||
| /// <summary> | ||||
| /// Represents a border. | ||||
| /// </summary> | ||||
| public abstract partial class BoxBorder | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Represents a border. | ||||
|     /// Gets an invisible border. | ||||
|     /// </summary> | ||||
|     public abstract partial class BoxBorder | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Gets an invisible border. | ||||
|         /// </summary> | ||||
|         public static BoxBorder None { get; } = new NoBoxBorder(); | ||||
|     public static BoxBorder None { get; } = new NoBoxBorder(); | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets an ASCII border. | ||||
|         /// </summary> | ||||
|         public static BoxBorder Ascii { get; } = new AsciiBoxBorder(); | ||||
|     /// <summary> | ||||
|     /// Gets an ASCII border. | ||||
|     /// </summary> | ||||
|     public static BoxBorder Ascii { get; } = new AsciiBoxBorder(); | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets a double border. | ||||
|         /// </summary> | ||||
|         [SuppressMessage("Naming", "CA1720:Identifier contains type name")] | ||||
|         public static BoxBorder Double { get; } = new DoubleBoxBorder(); | ||||
|     /// <summary> | ||||
|     /// Gets a double border. | ||||
|     /// </summary> | ||||
|     [SuppressMessage("Naming", "CA1720:Identifier contains type name")] | ||||
|     public static BoxBorder Double { get; } = new DoubleBoxBorder(); | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets a heavy border. | ||||
|         /// </summary> | ||||
|         public static BoxBorder Heavy { get; } = new HeavyBoxBorder(); | ||||
|     /// <summary> | ||||
|     /// Gets a heavy border. | ||||
|     /// </summary> | ||||
|     public static BoxBorder Heavy { get; } = new HeavyBoxBorder(); | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets a rounded border. | ||||
|         /// </summary> | ||||
|         public static BoxBorder Rounded { get; } = new RoundedBoxBorder(); | ||||
|     /// <summary> | ||||
|     /// Gets a rounded border. | ||||
|     /// </summary> | ||||
|     public static BoxBorder Rounded { get; } = new RoundedBoxBorder(); | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets a square border. | ||||
|         /// </summary> | ||||
|         public static BoxBorder Square { get; } = new SquareBoxBorder(); | ||||
|     } | ||||
| } | ||||
|     /// <summary> | ||||
|     /// Gets a square border. | ||||
|     /// </summary> | ||||
|     public static BoxBorder Square { get; } = new SquareBoxBorder(); | ||||
| } | ||||
| @@ -1,22 +1,21 @@ | ||||
| using Spectre.Console.Rendering; | ||||
|  | ||||
| namespace Spectre.Console | ||||
| namespace Spectre.Console; | ||||
|  | ||||
| /// <summary> | ||||
| /// Represents a border. | ||||
| /// </summary> | ||||
| public abstract partial class BoxBorder | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Represents a border. | ||||
|     /// Gets the safe border for this border or <c>null</c> if none exist. | ||||
|     /// </summary> | ||||
|     public abstract partial class BoxBorder | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Gets the safe border for this border or <c>null</c> if none exist. | ||||
|         /// </summary> | ||||
|         public virtual BoxBorder? SafeBorder { get; } | ||||
|     public virtual BoxBorder? SafeBorder { get; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets the string representation of the specified border part. | ||||
|         /// </summary> | ||||
|         /// <param name="part">The part to get the character representation for.</param> | ||||
|         /// <returns>A character representation of the specified border part.</returns> | ||||
|         public abstract string GetPart(BoxBorderPart part); | ||||
|     } | ||||
| } | ||||
|     /// <summary> | ||||
|     /// Gets the string representation of the specified border part. | ||||
|     /// </summary> | ||||
|     /// <param name="part">The part to get the character representation for.</param> | ||||
|     /// <returns>A character representation of the specified border part.</returns> | ||||
|     public abstract string GetPart(BoxBorderPart part); | ||||
| } | ||||
| @@ -1,73 +1,72 @@ | ||||
| using System; | ||||
|  | ||||
| namespace Spectre.Console | ||||
| namespace Spectre.Console; | ||||
|  | ||||
| /// <summary> | ||||
| /// Represents console capabilities. | ||||
| /// </summary> | ||||
| public sealed class Capabilities : IReadOnlyCapabilities | ||||
| { | ||||
|     private readonly IAnsiConsoleOutput _out; | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Represents console capabilities. | ||||
|     /// Gets or sets the color system. | ||||
|     /// </summary> | ||||
|     public sealed class Capabilities : IReadOnlyCapabilities | ||||
|     public ColorSystem ColorSystem { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Gets or sets a value indicating whether or not | ||||
|     /// the console supports VT/ANSI control codes. | ||||
|     /// </summary> | ||||
|     public bool Ansi { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Gets or sets a value indicating whether or not | ||||
|     /// the console support links. | ||||
|     /// </summary> | ||||
|     public bool Links { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Gets or sets a value indicating whether or not | ||||
|     /// this is a legacy console (cmd.exe) on an OS | ||||
|     /// prior to Windows 10. | ||||
|     /// </summary> | ||||
|     /// <remarks> | ||||
|     /// Only relevant when running on Microsoft Windows. | ||||
|     /// </remarks> | ||||
|     public bool Legacy { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Gets a value indicating whether or not | ||||
|     /// the output is a terminal. | ||||
|     /// </summary> | ||||
|     [Obsolete("Use Profile.Out.IsTerminal instead")] | ||||
|     public bool IsTerminal => _out.IsTerminal; | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Gets or sets a value indicating whether | ||||
|     /// or not the console supports interaction. | ||||
|     /// </summary> | ||||
|     public bool Interactive { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Gets or sets a value indicating whether | ||||
|     /// or not the console supports Unicode. | ||||
|     /// </summary> | ||||
|     public bool Unicode { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Gets or sets a value indicating whether | ||||
|     /// or not the console supports alternate buffers. | ||||
|     /// </summary> | ||||
|     public bool AlternateBuffer { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Initializes a new instance of the | ||||
|     /// <see cref="Capabilities"/> class. | ||||
|     /// </summary> | ||||
|     internal Capabilities(IAnsiConsoleOutput @out) | ||||
|     { | ||||
|         private readonly IAnsiConsoleOutput _out; | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets or sets the color system. | ||||
|         /// </summary> | ||||
|         public ColorSystem ColorSystem { get; set; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets or sets a value indicating whether or not | ||||
|         /// the console supports VT/ANSI control codes. | ||||
|         /// </summary> | ||||
|         public bool Ansi { get; set; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets or sets a value indicating whether or not | ||||
|         /// the console support links. | ||||
|         /// </summary> | ||||
|         public bool Links { get; set; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets or sets a value indicating whether or not | ||||
|         /// this is a legacy console (cmd.exe) on an OS | ||||
|         /// prior to Windows 10. | ||||
|         /// </summary> | ||||
|         /// <remarks> | ||||
|         /// Only relevant when running on Microsoft Windows. | ||||
|         /// </remarks> | ||||
|         public bool Legacy { get; set; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets a value indicating whether or not | ||||
|         /// the output is a terminal. | ||||
|         /// </summary> | ||||
|         [Obsolete("Use Profile.Out.IsTerminal instead")] | ||||
|         public bool IsTerminal => _out.IsTerminal; | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets or sets a value indicating whether | ||||
|         /// or not the console supports interaction. | ||||
|         /// </summary> | ||||
|         public bool Interactive { get; set; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets or sets a value indicating whether | ||||
|         /// or not the console supports Unicode. | ||||
|         /// </summary> | ||||
|         public bool Unicode { get; set; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets or sets a value indicating whether | ||||
|         /// or not the console supports alternate buffers. | ||||
|         /// </summary> | ||||
|         public bool AlternateBuffer { get; set; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Initializes a new instance of the | ||||
|         /// <see cref="Capabilities"/> class. | ||||
|         /// </summary> | ||||
|         internal Capabilities(IAnsiConsoleOutput @out) | ||||
|         { | ||||
|             _out = @out ?? throw new ArgumentNullException(nameof(@out)); | ||||
|         } | ||||
|         _out = @out ?? throw new ArgumentNullException(nameof(@out)); | ||||
|     } | ||||
| } | ||||
| } | ||||
| @@ -1,53 +1,52 @@ | ||||
| using System; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| /// <summary> | ||||
| /// An attribute representing a command argument. | ||||
| /// </summary> | ||||
| /// <seealso cref="Attribute" /> | ||||
| [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] | ||||
| public sealed class CommandArgumentAttribute : Attribute | ||||
| { | ||||
|     /// <summary> | ||||
|     /// An attribute representing a command argument. | ||||
|     /// Gets the argument position. | ||||
|     /// </summary> | ||||
|     /// <seealso cref="Attribute" /> | ||||
|     [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] | ||||
|     public sealed class CommandArgumentAttribute : Attribute | ||||
|     /// <value>The argument position.</value> | ||||
|     public int Position { get; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Gets the value name of the argument. | ||||
|     /// </summary> | ||||
|     /// <value>The value name of the argument.</value> | ||||
|     public string ValueName { get; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Gets a value indicating whether the argument is required. | ||||
|     /// </summary> | ||||
|     /// <value> | ||||
|     ///   <c>true</c> if the argument is required; otherwise, <c>false</c>. | ||||
|     /// </value> | ||||
|     public bool IsRequired { get; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Initializes a new instance of the <see cref="CommandArgumentAttribute"/> class. | ||||
|     /// </summary> | ||||
|     /// <param name="position">The argument position.</param> | ||||
|     /// <param name="template">The argument template.</param> | ||||
|     public CommandArgumentAttribute(int position, string template) | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Gets the argument position. | ||||
|         /// </summary> | ||||
|         /// <value>The argument position.</value> | ||||
|         public int Position { get; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets the value name of the argument. | ||||
|         /// </summary> | ||||
|         /// <value>The value name of the argument.</value> | ||||
|         public string ValueName { get; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets a value indicating whether the argument is required. | ||||
|         /// </summary> | ||||
|         /// <value> | ||||
|         ///   <c>true</c> if the argument is required; otherwise, <c>false</c>. | ||||
|         /// </value> | ||||
|         public bool IsRequired { get; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Initializes a new instance of the <see cref="CommandArgumentAttribute"/> class. | ||||
|         /// </summary> | ||||
|         /// <param name="position">The argument position.</param> | ||||
|         /// <param name="template">The argument template.</param> | ||||
|         public CommandArgumentAttribute(int position, string template) | ||||
|         if (template == null) | ||||
|         { | ||||
|             if (template == null) | ||||
|             { | ||||
|                 throw new ArgumentNullException(nameof(template)); | ||||
|             } | ||||
|  | ||||
|             // Parse the option template. | ||||
|             var result = TemplateParser.ParseArgumentTemplate(template); | ||||
|  | ||||
|             // Assign the result. | ||||
|             Position = position; | ||||
|             ValueName = result.Value; | ||||
|             IsRequired = result.Required; | ||||
|             throw new ArgumentNullException(nameof(template)); | ||||
|         } | ||||
|  | ||||
|         // Parse the option template. | ||||
|         var result = TemplateParser.ParseArgumentTemplate(template); | ||||
|  | ||||
|         // Assign the result. | ||||
|         Position = position; | ||||
|         ValueName = result.Value; | ||||
|         IsRequired = result.Required; | ||||
|     } | ||||
| } | ||||
| } | ||||
| @@ -2,69 +2,68 @@ using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| /// <summary> | ||||
| /// An attribute representing a command option. | ||||
| /// </summary> | ||||
| /// <seealso cref="Attribute" /> | ||||
| [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] | ||||
| public sealed class CommandOptionAttribute : Attribute | ||||
| { | ||||
|     /// <summary> | ||||
|     /// An attribute representing a command option. | ||||
|     /// Gets the long names of the option. | ||||
|     /// </summary> | ||||
|     /// <seealso cref="Attribute" /> | ||||
|     [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] | ||||
|     public sealed class CommandOptionAttribute : Attribute | ||||
|     /// <value>The option's long names.</value> | ||||
|     public IReadOnlyList<string> LongNames { get; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Gets the short names of the option. | ||||
|     /// </summary> | ||||
|     /// <value>The option's short names.</value> | ||||
|     public IReadOnlyList<string> ShortNames { get; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Gets the value name of the option. | ||||
|     /// </summary> | ||||
|     /// <value>The option's value name.</value> | ||||
|     public string? ValueName { get; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Gets a value indicating whether the value is optional. | ||||
|     /// </summary> | ||||
|     public bool ValueIsOptional { get; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Gets or sets a value indicating whether this option is hidden from the help text. | ||||
|     /// </summary> | ||||
|     public bool IsHidden { get; set; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Initializes a new instance of the <see cref="CommandOptionAttribute"/> class. | ||||
|     /// </summary> | ||||
|     /// <param name="template">The option template.</param> | ||||
|     public CommandOptionAttribute(string template) | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Gets the long names of the option. | ||||
|         /// </summary> | ||||
|         /// <value>The option's long names.</value> | ||||
|         public IReadOnlyList<string> LongNames { get; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets the short names of the option. | ||||
|         /// </summary> | ||||
|         /// <value>The option's short names.</value> | ||||
|         public IReadOnlyList<string> ShortNames { get; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets the value name of the option. | ||||
|         /// </summary> | ||||
|         /// <value>The option's value name.</value> | ||||
|         public string? ValueName { get; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets a value indicating whether the value is optional. | ||||
|         /// </summary> | ||||
|         public bool ValueIsOptional { get; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets or sets a value indicating whether this option is hidden from the help text. | ||||
|         /// </summary> | ||||
|         public bool IsHidden { get; set; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Initializes a new instance of the <see cref="CommandOptionAttribute"/> class. | ||||
|         /// </summary> | ||||
|         /// <param name="template">The option template.</param> | ||||
|         public CommandOptionAttribute(string template) | ||||
|         if (template == null) | ||||
|         { | ||||
|             if (template == null) | ||||
|             { | ||||
|                 throw new ArgumentNullException(nameof(template)); | ||||
|             } | ||||
|  | ||||
|             // Parse the option template. | ||||
|             var result = TemplateParser.ParseOptionTemplate(template); | ||||
|  | ||||
|             // Assign the result. | ||||
|             LongNames = result.LongNames; | ||||
|             ShortNames = result.ShortNames; | ||||
|             ValueName = result.Value; | ||||
|             ValueIsOptional = result.ValueIsOptional; | ||||
|             throw new ArgumentNullException(nameof(template)); | ||||
|         } | ||||
|  | ||||
|         internal bool IsMatch(string name) | ||||
|         { | ||||
|             return | ||||
|                 ShortNames.Contains(name, StringComparer.Ordinal) || | ||||
|                 LongNames.Contains(name, StringComparer.Ordinal); | ||||
|         } | ||||
|         // Parse the option template. | ||||
|         var result = TemplateParser.ParseOptionTemplate(template); | ||||
|  | ||||
|         // Assign the result. | ||||
|         LongNames = result.LongNames; | ||||
|         ShortNames = result.ShortNames; | ||||
|         ValueName = result.Value; | ||||
|         ValueIsOptional = result.ValueIsOptional; | ||||
|     } | ||||
| } | ||||
|  | ||||
|     internal bool IsMatch(string name) | ||||
|     { | ||||
|         return | ||||
|             ShortNames.Contains(name, StringComparer.Ordinal) || | ||||
|             LongNames.Contains(name, StringComparer.Ordinal); | ||||
|     } | ||||
| } | ||||
| @@ -1,31 +1,30 @@ | ||||
| using System; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| /// <summary> | ||||
| /// Specifies what type to use as a pair deconstructor for | ||||
| /// the property this attribute is bound to. | ||||
| /// </summary> | ||||
| [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] | ||||
| public sealed class PairDeconstructorAttribute : Attribute | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Specifies what type to use as a pair deconstructor for | ||||
|     /// the property this attribute is bound to. | ||||
|     /// Gets the <see cref="string"/> that represents the type of the | ||||
|     /// pair deconstructor class to use for data conversion for the | ||||
|     /// object this attribute is bound to. | ||||
|     /// </summary> | ||||
|     [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] | ||||
|     public sealed class PairDeconstructorAttribute : Attribute | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Gets the <see cref="string"/> that represents the type of the | ||||
|         /// pair deconstructor class to use for data conversion for the | ||||
|         /// object this attribute is bound to. | ||||
|         /// </summary> | ||||
|         public Type Type { get; } | ||||
|     public Type Type { get; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Initializes a new instance of the <see cref="PairDeconstructorAttribute"/> class. | ||||
|         /// </summary> | ||||
|         /// <param name="type"> | ||||
|         ///     A System.Type that represents the type of the pair deconstructor | ||||
|         ///     class to use for data conversion for the object this attribute is bound to. | ||||
|         /// </param> | ||||
|         public PairDeconstructorAttribute(Type type) | ||||
|         { | ||||
|             Type = type ?? throw new ArgumentNullException(nameof(type)); | ||||
|         } | ||||
|     /// <summary> | ||||
|     /// Initializes a new instance of the <see cref="PairDeconstructorAttribute"/> class. | ||||
|     /// </summary> | ||||
|     /// <param name="type"> | ||||
|     ///     A System.Type that represents the type of the pair deconstructor | ||||
|     ///     class to use for data conversion for the object this attribute is bound to. | ||||
|     /// </param> | ||||
|     public PairDeconstructorAttribute(Type type) | ||||
|     { | ||||
|         Type = type ?? throw new ArgumentNullException(nameof(type)); | ||||
|     } | ||||
| } | ||||
| } | ||||
| @@ -1,34 +1,33 @@ | ||||
| using System; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| /// <summary> | ||||
| /// A base class attribute used for parameter validation. | ||||
| /// </summary> | ||||
| /// <seealso cref="Attribute" /> | ||||
| [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)] | ||||
| public abstract class ParameterValidationAttribute : Attribute | ||||
| { | ||||
|     /// <summary> | ||||
|     /// A base class attribute used for parameter validation. | ||||
|     /// Gets the validation error message. | ||||
|     /// </summary> | ||||
|     /// <seealso cref="Attribute" /> | ||||
|     [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)] | ||||
|     public abstract class ParameterValidationAttribute : Attribute | ||||
|     /// <value>The validation error message.</value> | ||||
|     public string ErrorMessage { get; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Initializes a new instance of the <see cref="ParameterValidationAttribute"/> class. | ||||
|     /// </summary> | ||||
|     /// <param name="errorMessage">The validation error message.</param> | ||||
|     protected ParameterValidationAttribute(string errorMessage) | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Gets the validation error message. | ||||
|         /// </summary> | ||||
|         /// <value>The validation error message.</value> | ||||
|         public string ErrorMessage { get; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Initializes a new instance of the <see cref="ParameterValidationAttribute"/> class. | ||||
|         /// </summary> | ||||
|         /// <param name="errorMessage">The validation error message.</param> | ||||
|         protected ParameterValidationAttribute(string errorMessage) | ||||
|         { | ||||
|             ErrorMessage = errorMessage; | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Validates the parameter value. | ||||
|         /// </summary> | ||||
|         /// <param name="context">The parameter context.</param> | ||||
|         /// <returns>The validation result.</returns> | ||||
|         public abstract ValidationResult Validate(CommandParameterContext context); | ||||
|         ErrorMessage = errorMessage; | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Validates the parameter value. | ||||
|     /// </summary> | ||||
|     /// <param name="context">The parameter context.</param> | ||||
|     /// <returns>The validation result.</returns> | ||||
|     public abstract ValidationResult Validate(CommandParameterContext context); | ||||
| } | ||||
| @@ -1,20 +1,19 @@ | ||||
| using System; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| /// <summary> | ||||
| /// A base class attribute used for parameter completion. | ||||
| /// </summary> | ||||
| /// <seealso cref="Attribute" /> | ||||
| [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] | ||||
| public abstract class ParameterValueProviderAttribute : Attribute | ||||
| { | ||||
|     /// <summary> | ||||
|     /// A base class attribute used for parameter completion. | ||||
|     /// Gets a value for the parameter. | ||||
|     /// </summary> | ||||
|     /// <seealso cref="Attribute" /> | ||||
|     [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] | ||||
|     public abstract class ParameterValueProviderAttribute : Attribute | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Gets a value for the parameter. | ||||
|         /// </summary> | ||||
|         /// <param name="context">The parameter context.</param> | ||||
|         /// <param name="result">The resulting value.</param> | ||||
|         /// <returns><c>true</c> if a value was provided; otherwise, <c>false</c>.</returns> | ||||
|         public abstract bool TryGetValue(CommandParameterContext context, out object? result); | ||||
|     } | ||||
| } | ||||
|     /// <param name="context">The parameter context.</param> | ||||
|     /// <param name="result">The resulting value.</param> | ||||
|     /// <returns><c>true</c> if a value was provided; otherwise, <c>false</c>.</returns> | ||||
|     public abstract bool TryGetValue(CommandParameterContext context, out object? result); | ||||
| } | ||||
| @@ -1,35 +1,34 @@ | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| /// <summary> | ||||
| /// Base class for an asynchronous command with no settings. | ||||
| /// </summary> | ||||
| public abstract class AsyncCommand : ICommand<EmptyCommandSettings> | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Base class for an asynchronous command with no settings. | ||||
|     /// Executes the command. | ||||
|     /// </summary> | ||||
|     public abstract class AsyncCommand : ICommand<EmptyCommandSettings> | ||||
|     /// <param name="context">The command context.</param> | ||||
|     /// <returns>An integer indicating whether or not the command executed successfully.</returns> | ||||
|     public abstract Task<int> ExecuteAsync(CommandContext context); | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     Task<int> ICommand<EmptyCommandSettings>.Execute(CommandContext context, EmptyCommandSettings settings) | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Executes the command. | ||||
|         /// </summary> | ||||
|         /// <param name="context">The command context.</param> | ||||
|         /// <returns>An integer indicating whether or not the command executed successfully.</returns> | ||||
|         public abstract Task<int> ExecuteAsync(CommandContext context); | ||||
|         return ExecuteAsync(context); | ||||
|     } | ||||
|  | ||||
|         /// <inheritdoc/> | ||||
|         Task<int> ICommand<EmptyCommandSettings>.Execute(CommandContext context, EmptyCommandSettings settings) | ||||
|         { | ||||
|             return ExecuteAsync(context); | ||||
|         } | ||||
|     /// <inheritdoc/> | ||||
|     Task<int> ICommand.Execute(CommandContext context, CommandSettings settings) | ||||
|     { | ||||
|         return ExecuteAsync(context); | ||||
|     } | ||||
|  | ||||
|         /// <inheritdoc/> | ||||
|         Task<int> ICommand.Execute(CommandContext context, CommandSettings settings) | ||||
|         { | ||||
|             return ExecuteAsync(context); | ||||
|         } | ||||
|  | ||||
|         /// <inheritdoc/> | ||||
|         ValidationResult ICommand.Validate(CommandContext context, CommandSettings settings) | ||||
|         { | ||||
|             return ValidationResult.Success(); | ||||
|         } | ||||
|     /// <inheritdoc/> | ||||
|     ValidationResult ICommand.Validate(CommandContext context, CommandSettings settings) | ||||
|     { | ||||
|         return ValidationResult.Success(); | ||||
|     } | ||||
| } | ||||
| @@ -1,51 +1,50 @@ | ||||
| using System.Diagnostics; | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| /// <summary> | ||||
| /// Base class for an asynchronous command. | ||||
| /// </summary> | ||||
| /// <typeparam name="TSettings">The settings type.</typeparam> | ||||
| public abstract class AsyncCommand<TSettings> : ICommand<TSettings> | ||||
|     where TSettings : CommandSettings | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Base class for an asynchronous command. | ||||
|     /// Validates the specified settings and remaining arguments. | ||||
|     /// </summary> | ||||
|     /// <typeparam name="TSettings">The settings type.</typeparam> | ||||
|     public abstract class AsyncCommand<TSettings> : ICommand<TSettings> | ||||
|         where TSettings : CommandSettings | ||||
|     /// <param name="context">The command context.</param> | ||||
|     /// <param name="settings">The settings.</param> | ||||
|     /// <returns>The validation result.</returns> | ||||
|     public virtual ValidationResult Validate(CommandContext context, TSettings settings) | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Validates the specified settings and remaining arguments. | ||||
|         /// </summary> | ||||
|         /// <param name="context">The command context.</param> | ||||
|         /// <param name="settings">The settings.</param> | ||||
|         /// <returns>The validation result.</returns> | ||||
|         public virtual ValidationResult Validate(CommandContext context, TSettings settings) | ||||
|         { | ||||
|             return ValidationResult.Success(); | ||||
|         } | ||||
|         return ValidationResult.Success(); | ||||
|     } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Executes the command. | ||||
|         /// </summary> | ||||
|         /// <param name="context">The command context.</param> | ||||
|         /// <param name="settings">The settings.</param> | ||||
|         /// <returns>An integer indicating whether or not the command executed successfully.</returns> | ||||
|         public abstract Task<int> ExecuteAsync(CommandContext context, TSettings settings); | ||||
|     /// <summary> | ||||
|     /// Executes the command. | ||||
|     /// </summary> | ||||
|     /// <param name="context">The command context.</param> | ||||
|     /// <param name="settings">The settings.</param> | ||||
|     /// <returns>An integer indicating whether or not the command executed successfully.</returns> | ||||
|     public abstract Task<int> ExecuteAsync(CommandContext context, TSettings settings); | ||||
|  | ||||
|         /// <inheritdoc/> | ||||
|         ValidationResult ICommand.Validate(CommandContext context, CommandSettings settings) | ||||
|         { | ||||
|             return Validate(context, (TSettings)settings); | ||||
|         } | ||||
|     /// <inheritdoc/> | ||||
|     ValidationResult ICommand.Validate(CommandContext context, CommandSettings settings) | ||||
|     { | ||||
|         return Validate(context, (TSettings)settings); | ||||
|     } | ||||
|  | ||||
|         /// <inheritdoc/> | ||||
|         Task<int> ICommand.Execute(CommandContext context, CommandSettings settings) | ||||
|         { | ||||
|             Debug.Assert(settings is TSettings, "Command settings is of unexpected type."); | ||||
|             return ExecuteAsync(context, (TSettings)settings); | ||||
|         } | ||||
|     /// <inheritdoc/> | ||||
|     Task<int> ICommand.Execute(CommandContext context, CommandSettings settings) | ||||
|     { | ||||
|         Debug.Assert(settings is TSettings, "Command settings is of unexpected type."); | ||||
|         return ExecuteAsync(context, (TSettings)settings); | ||||
|     } | ||||
|  | ||||
|         /// <inheritdoc/> | ||||
|         Task<int> ICommand<TSettings>.Execute(CommandContext context, TSettings settings) | ||||
|         { | ||||
|             return ExecuteAsync(context, settings); | ||||
|         } | ||||
|     /// <inheritdoc/> | ||||
|     Task<int> ICommand<TSettings>.Execute(CommandContext context, TSettings settings) | ||||
|     { | ||||
|         return ExecuteAsync(context, settings); | ||||
|     } | ||||
| } | ||||
| @@ -1,31 +1,30 @@ | ||||
| using System; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| /// <summary> | ||||
| /// Represents case sensitivity. | ||||
| /// </summary> | ||||
| [Flags] | ||||
| public enum CaseSensitivity | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Represents case sensitivity. | ||||
|     /// Nothing is case sensitive. | ||||
|     /// </summary> | ||||
|     [Flags] | ||||
|     public enum CaseSensitivity | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Nothing is case sensitive. | ||||
|         /// </summary> | ||||
|         None = 0, | ||||
|     None = 0, | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Long options are case sensitive. | ||||
|         /// </summary> | ||||
|         LongOptions = 1, | ||||
|     /// <summary> | ||||
|     /// Long options are case sensitive. | ||||
|     /// </summary> | ||||
|     LongOptions = 1, | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Commands are case sensitive. | ||||
|         /// </summary> | ||||
|         Commands = 2, | ||||
|     /// <summary> | ||||
|     /// Commands are case sensitive. | ||||
|     /// </summary> | ||||
|     Commands = 2, | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Everything is case sensitive. | ||||
|         /// </summary> | ||||
|         All = LongOptions | Commands, | ||||
|     } | ||||
| } | ||||
|     /// <summary> | ||||
|     /// Everything is case sensitive. | ||||
|     /// </summary> | ||||
|     All = LongOptions | Commands, | ||||
| } | ||||
| @@ -1,36 +1,35 @@ | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| /// <summary> | ||||
| /// Base class for a command without settings. | ||||
| /// </summary> | ||||
| /// <seealso cref="AsyncCommand"/> | ||||
| public abstract class Command : ICommand<EmptyCommandSettings> | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Base class for a command without settings. | ||||
|     /// Executes the command. | ||||
|     /// </summary> | ||||
|     /// <seealso cref="AsyncCommand"/> | ||||
|     public abstract class Command : ICommand<EmptyCommandSettings> | ||||
|     /// <param name="context">The command context.</param> | ||||
|     /// <returns>An integer indicating whether or not the command executed successfully.</returns> | ||||
|     public abstract int Execute(CommandContext context); | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     Task<int> ICommand<EmptyCommandSettings>.Execute(CommandContext context, EmptyCommandSettings settings) | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Executes the command. | ||||
|         /// </summary> | ||||
|         /// <param name="context">The command context.</param> | ||||
|         /// <returns>An integer indicating whether or not the command executed successfully.</returns> | ||||
|         public abstract int Execute(CommandContext context); | ||||
|  | ||||
|         /// <inheritdoc/> | ||||
|         Task<int> ICommand<EmptyCommandSettings>.Execute(CommandContext context, EmptyCommandSettings settings) | ||||
|         { | ||||
|             return Task.FromResult(Execute(context)); | ||||
|         } | ||||
|  | ||||
|         /// <inheritdoc/> | ||||
|         Task<int> ICommand.Execute(CommandContext context, CommandSettings settings) | ||||
|         { | ||||
|             return Task.FromResult(Execute(context)); | ||||
|         } | ||||
|  | ||||
|         /// <inheritdoc/> | ||||
|         ValidationResult ICommand.Validate(CommandContext context, CommandSettings settings) | ||||
|         { | ||||
|             return ValidationResult.Success(); | ||||
|         } | ||||
|         return Task.FromResult(Execute(context)); | ||||
|     } | ||||
| } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     Task<int> ICommand.Execute(CommandContext context, CommandSettings settings) | ||||
|     { | ||||
|         return Task.FromResult(Execute(context)); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     ValidationResult ICommand.Validate(CommandContext context, CommandSettings settings) | ||||
|     { | ||||
|         return ValidationResult.Success(); | ||||
|     } | ||||
| } | ||||
| @@ -4,136 +4,136 @@ using System.Diagnostics; | ||||
| using System.Threading.Tasks; | ||||
| using Spectre.Console.Rendering; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| /// <summary> | ||||
| /// The entry point for a command line application. | ||||
| /// </summary> | ||||
| public sealed class CommandApp : ICommandApp | ||||
| { | ||||
|     private readonly Configurator _configurator; | ||||
|     private readonly CommandExecutor _executor; | ||||
|     private bool _executed; | ||||
|  | ||||
|     /// <summary> | ||||
|     /// The entry point for a command line application. | ||||
|     /// Initializes a new instance of the <see cref="CommandApp"/> class. | ||||
|     /// </summary> | ||||
|     public sealed class CommandApp : ICommandApp | ||||
|     /// <param name="registrar">The registrar.</param> | ||||
|     public CommandApp(ITypeRegistrar? registrar = null) | ||||
|     { | ||||
|         private readonly Configurator _configurator; | ||||
|         private readonly CommandExecutor _executor; | ||||
|         private bool _executed; | ||||
|         registrar ??= new DefaultTypeRegistrar(); | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Initializes a new instance of the <see cref="CommandApp"/> class. | ||||
|         /// </summary> | ||||
|         /// <param name="registrar">The registrar.</param> | ||||
|         public CommandApp(ITypeRegistrar? registrar = null) | ||||
|         _configurator = new Configurator(registrar); | ||||
|         _executor = new CommandExecutor(registrar); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Configures the command line application. | ||||
|     /// </summary> | ||||
|     /// <param name="configuration">The configuration.</param> | ||||
|     public void Configure(Action<IConfigurator> configuration) | ||||
|     { | ||||
|         if (configuration == null) | ||||
|         { | ||||
|             registrar ??= new DefaultTypeRegistrar(); | ||||
|  | ||||
|             _configurator = new Configurator(registrar); | ||||
|             _executor = new CommandExecutor(registrar); | ||||
|             throw new ArgumentNullException(nameof(configuration)); | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Configures the command line application. | ||||
|         /// </summary> | ||||
|         /// <param name="configuration">The configuration.</param> | ||||
|         public void Configure(Action<IConfigurator> configuration) | ||||
|         configuration(_configurator); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Sets the default command. | ||||
|     /// </summary> | ||||
|     /// <typeparam name="TCommand">The command type.</typeparam> | ||||
|     public void SetDefaultCommand<TCommand>() | ||||
|         where TCommand : class, ICommand | ||||
|     { | ||||
|         GetConfigurator().SetDefaultCommand<TCommand>(); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Runs the command line application with specified arguments. | ||||
|     /// </summary> | ||||
|     /// <param name="args">The arguments.</param> | ||||
|     /// <returns>The exit code from the executed command.</returns> | ||||
|     public int Run(IEnumerable<string> args) | ||||
|     { | ||||
|         return RunAsync(args).GetAwaiter().GetResult(); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Runs the command line application with specified arguments. | ||||
|     /// </summary> | ||||
|     /// <param name="args">The arguments.</param> | ||||
|     /// <returns>The exit code from the executed command.</returns> | ||||
|     public async Task<int> RunAsync(IEnumerable<string> args) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             if (configuration == null) | ||||
|             if (!_executed) | ||||
|             { | ||||
|                 throw new ArgumentNullException(nameof(configuration)); | ||||
|                 // Add built-in (hidden) commands. | ||||
|                 _configurator.AddBranch(CliConstants.Commands.Branch, cli => | ||||
|                 { | ||||
|                     cli.HideBranch(); | ||||
|                     cli.AddCommand<VersionCommand>(CliConstants.Commands.Version); | ||||
|                     cli.AddCommand<XmlDocCommand>(CliConstants.Commands.XmlDoc); | ||||
|                     cli.AddCommand<ExplainCommand>(CliConstants.Commands.Explain); | ||||
|                 }); | ||||
|  | ||||
|                 _executed = true; | ||||
|             } | ||||
|  | ||||
|             configuration(_configurator); | ||||
|             return await _executor | ||||
|                 .Execute(_configurator, args) | ||||
|                 .ConfigureAwait(false); | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Sets the default command. | ||||
|         /// </summary> | ||||
|         /// <typeparam name="TCommand">The command type.</typeparam> | ||||
|         public void SetDefaultCommand<TCommand>() | ||||
|             where TCommand : class, ICommand | ||||
|         catch (Exception ex) | ||||
|         { | ||||
|             GetConfigurator().SetDefaultCommand<TCommand>(); | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Runs the command line application with specified arguments. | ||||
|         /// </summary> | ||||
|         /// <param name="args">The arguments.</param> | ||||
|         /// <returns>The exit code from the executed command.</returns> | ||||
|         public int Run(IEnumerable<string> args) | ||||
|         { | ||||
|             return RunAsync(args).GetAwaiter().GetResult(); | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Runs the command line application with specified arguments. | ||||
|         /// </summary> | ||||
|         /// <param name="args">The arguments.</param> | ||||
|         /// <returns>The exit code from the executed command.</returns> | ||||
|         public async Task<int> RunAsync(IEnumerable<string> args) | ||||
|         { | ||||
|             try | ||||
|             // Should we always propagate when debugging? | ||||
|             if (Debugger.IsAttached | ||||
|                 && ex is CommandAppException appException | ||||
|                 && appException.AlwaysPropagateWhenDebugging) | ||||
|             { | ||||
|                 if (!_executed) | ||||
|                 { | ||||
|                     // Add built-in (hidden) commands. | ||||
|                     _configurator.AddBranch(CliConstants.Commands.Branch, cli => | ||||
|                     { | ||||
|                         cli.HideBranch(); | ||||
|                         cli.AddCommand<VersionCommand>(CliConstants.Commands.Version); | ||||
|                         cli.AddCommand<XmlDocCommand>(CliConstants.Commands.XmlDoc); | ||||
|                         cli.AddCommand<ExplainCommand>(CliConstants.Commands.Explain); | ||||
|                     }); | ||||
|  | ||||
|                     _executed = true; | ||||
|                 } | ||||
|  | ||||
|                 return await _executor | ||||
|                     .Execute(_configurator, args) | ||||
|                     .ConfigureAwait(false); | ||||
|             } | ||||
|             catch (Exception ex) | ||||
|             { | ||||
|                 // Should we always propagate when debugging? | ||||
|                 if (Debugger.IsAttached | ||||
|                     && ex is CommandAppException appException | ||||
|                     && appException.AlwaysPropagateWhenDebugging) | ||||
|                 { | ||||
|                     throw; | ||||
|                 } | ||||
|  | ||||
|                 if (_configurator.Settings.PropagateExceptions) | ||||
|                 { | ||||
|                     throw; | ||||
|                 } | ||||
|  | ||||
|                 if (_configurator.Settings.ExceptionHandler != null) | ||||
|                 { | ||||
|                     return _configurator.Settings.ExceptionHandler(ex); | ||||
|                 } | ||||
|  | ||||
|                 // Render the exception. | ||||
|                 var pretty = GetRenderableErrorMessage(ex); | ||||
|                 if (pretty != null) | ||||
|                 { | ||||
|                     _configurator.Settings.Console.SafeRender(pretty); | ||||
|                 } | ||||
|  | ||||
|                 return -1; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         internal Configurator GetConfigurator() | ||||
|         { | ||||
|             return _configurator; | ||||
|         } | ||||
|  | ||||
|         private static List<IRenderable?>? GetRenderableErrorMessage(Exception ex, bool convert = true) | ||||
|         { | ||||
|             if (ex is CommandAppException renderable && renderable.Pretty != null) | ||||
|             { | ||||
|                 return new List<IRenderable?> { renderable.Pretty }; | ||||
|                 throw; | ||||
|             } | ||||
|  | ||||
|             if (convert) | ||||
|             if (_configurator.Settings.PropagateExceptions) | ||||
|             { | ||||
|                 var converted = new List<IRenderable?> | ||||
|                 throw; | ||||
|             } | ||||
|  | ||||
|             if (_configurator.Settings.ExceptionHandler != null) | ||||
|             { | ||||
|                 return _configurator.Settings.ExceptionHandler(ex); | ||||
|             } | ||||
|  | ||||
|             // Render the exception. | ||||
|             var pretty = GetRenderableErrorMessage(ex); | ||||
|             if (pretty != null) | ||||
|             { | ||||
|                 _configurator.Settings.Console.SafeRender(pretty); | ||||
|             } | ||||
|  | ||||
|             return -1; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     internal Configurator GetConfigurator() | ||||
|     { | ||||
|         return _configurator; | ||||
|     } | ||||
|  | ||||
|     private static List<IRenderable?>? GetRenderableErrorMessage(Exception ex, bool convert = true) | ||||
|     { | ||||
|         if (ex is CommandAppException renderable && renderable.Pretty != null) | ||||
|         { | ||||
|             return new List<IRenderable?> { renderable.Pretty }; | ||||
|         } | ||||
|  | ||||
|         if (convert) | ||||
|         { | ||||
|             var converted = new List<IRenderable?> | ||||
|                 { | ||||
|                     new Composer() | ||||
|                         .Text("[red]Error:[/]") | ||||
| @@ -142,20 +142,19 @@ namespace Spectre.Console.Cli | ||||
|                         .LineBreak(), | ||||
|                 }; | ||||
|  | ||||
|                 // Got a renderable inner exception? | ||||
|                 if (ex.InnerException != null) | ||||
|             // Got a renderable inner exception? | ||||
|             if (ex.InnerException != null) | ||||
|             { | ||||
|                 var innerRenderable = GetRenderableErrorMessage(ex.InnerException, convert: false); | ||||
|                 if (innerRenderable != null) | ||||
|                 { | ||||
|                     var innerRenderable = GetRenderableErrorMessage(ex.InnerException, convert: false); | ||||
|                     if (innerRenderable != null) | ||||
|                     { | ||||
|                         converted.AddRange(innerRenderable); | ||||
|                     } | ||||
|                     converted.AddRange(innerRenderable); | ||||
|                 } | ||||
|  | ||||
|                 return converted; | ||||
|             } | ||||
|  | ||||
|             return null; | ||||
|             return converted; | ||||
|         } | ||||
|  | ||||
|         return null; | ||||
|     } | ||||
| } | ||||
| } | ||||
| @@ -1,30 +1,29 @@ | ||||
| using System; | ||||
| using Spectre.Console.Rendering; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| /// <summary> | ||||
| /// Represents errors that occur during application execution. | ||||
| /// </summary> | ||||
| public abstract class CommandAppException : Exception | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Represents errors that occur during application execution. | ||||
|     /// Gets the pretty formatted exception message. | ||||
|     /// </summary> | ||||
|     public abstract class CommandAppException : Exception | ||||
|     public IRenderable? Pretty { get; } | ||||
|  | ||||
|     internal virtual bool AlwaysPropagateWhenDebugging => false; | ||||
|  | ||||
|     internal CommandAppException(string message, IRenderable? pretty = null) | ||||
|         : base(message) | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Gets the pretty formatted exception message. | ||||
|         /// </summary> | ||||
|         public IRenderable? Pretty { get; } | ||||
|         Pretty = pretty; | ||||
|     } | ||||
|  | ||||
|         internal virtual bool AlwaysPropagateWhenDebugging => false; | ||||
|  | ||||
|         internal CommandAppException(string message, IRenderable? pretty = null) | ||||
|             : base(message) | ||||
|         { | ||||
|             Pretty = pretty; | ||||
|         } | ||||
|  | ||||
|         internal CommandAppException(string message, Exception ex, IRenderable? pretty = null) | ||||
|             : base(message, ex) | ||||
|         { | ||||
|             Pretty = pretty; | ||||
|         } | ||||
|     internal CommandAppException(string message, Exception ex, IRenderable? pretty = null) | ||||
|         : base(message, ex) | ||||
|     { | ||||
|         Pretty = pretty; | ||||
|     } | ||||
| } | ||||
| @@ -2,54 +2,53 @@ using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| /// <summary> | ||||
| /// The entry point for a command line application with a default command. | ||||
| /// </summary> | ||||
| /// <typeparam name="TDefaultCommand">The type of the default command.</typeparam> | ||||
| public sealed class CommandApp<TDefaultCommand> : ICommandApp | ||||
|     where TDefaultCommand : class, ICommand | ||||
| { | ||||
|     private readonly CommandApp _app; | ||||
|  | ||||
|     /// <summary> | ||||
|     /// The entry point for a command line application with a default command. | ||||
|     /// Initializes a new instance of the <see cref="CommandApp{TDefaultCommand}"/> class. | ||||
|     /// </summary> | ||||
|     /// <typeparam name="TDefaultCommand">The type of the default command.</typeparam> | ||||
|     public sealed class CommandApp<TDefaultCommand> : ICommandApp | ||||
|         where TDefaultCommand : class, ICommand | ||||
|     /// <param name="registrar">The registrar.</param> | ||||
|     public CommandApp(ITypeRegistrar? registrar = null) | ||||
|     { | ||||
|         private readonly CommandApp _app; | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Initializes a new instance of the <see cref="CommandApp{TDefaultCommand}"/> class. | ||||
|         /// </summary> | ||||
|         /// <param name="registrar">The registrar.</param> | ||||
|         public CommandApp(ITypeRegistrar? registrar = null) | ||||
|         { | ||||
|             _app = new CommandApp(registrar); | ||||
|             _app.GetConfigurator().SetDefaultCommand<TDefaultCommand>(); | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Configures the command line application. | ||||
|         /// </summary> | ||||
|         /// <param name="configuration">The configuration.</param> | ||||
|         public void Configure(Action<IConfigurator> configuration) | ||||
|         { | ||||
|             _app.Configure(configuration); | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Runs the command line application with specified arguments. | ||||
|         /// </summary> | ||||
|         /// <param name="args">The arguments.</param> | ||||
|         /// <returns>The exit code from the executed command.</returns> | ||||
|         public int Run(IEnumerable<string> args) | ||||
|         { | ||||
|             return _app.Run(args); | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Runs the command line application with specified arguments. | ||||
|         /// </summary> | ||||
|         /// <param name="args">The arguments.</param> | ||||
|         /// <returns>The exit code from the executed command.</returns> | ||||
|         public Task<int> RunAsync(IEnumerable<string> args) | ||||
|         { | ||||
|             return _app.RunAsync(args); | ||||
|         } | ||||
|         _app = new CommandApp(registrar); | ||||
|         _app.GetConfigurator().SetDefaultCommand<TDefaultCommand>(); | ||||
|     } | ||||
| } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Configures the command line application. | ||||
|     /// </summary> | ||||
|     /// <param name="configuration">The configuration.</param> | ||||
|     public void Configure(Action<IConfigurator> configuration) | ||||
|     { | ||||
|         _app.Configure(configuration); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Runs the command line application with specified arguments. | ||||
|     /// </summary> | ||||
|     /// <param name="args">The arguments.</param> | ||||
|     /// <returns>The exit code from the executed command.</returns> | ||||
|     public int Run(IEnumerable<string> args) | ||||
|     { | ||||
|         return _app.Run(args); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Runs the command line application with specified arguments. | ||||
|     /// </summary> | ||||
|     /// <param name="args">The arguments.</param> | ||||
|     /// <returns>The exit code from the executed command.</returns> | ||||
|     public Task<int> RunAsync(IEnumerable<string> args) | ||||
|     { | ||||
|         return _app.RunAsync(args); | ||||
|     } | ||||
| } | ||||
| @@ -2,80 +2,79 @@ using System; | ||||
| using System.Linq; | ||||
| using Spectre.Console.Rendering; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| /// <summary> | ||||
| /// Represents errors that occur during configuration. | ||||
| /// </summary> | ||||
| public class CommandConfigurationException : CommandAppException | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Represents errors that occur during configuration. | ||||
|     /// </summary> | ||||
|     public class CommandConfigurationException : CommandAppException | ||||
|     internal override bool AlwaysPropagateWhenDebugging => true; | ||||
|  | ||||
|     internal CommandConfigurationException(string message, IRenderable? pretty = null) | ||||
|         : base(message, pretty) | ||||
|     { | ||||
|         internal override bool AlwaysPropagateWhenDebugging => true; | ||||
|  | ||||
|         internal CommandConfigurationException(string message, IRenderable? pretty = null) | ||||
|             : base(message, pretty) | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         internal CommandConfigurationException(string message, Exception ex, IRenderable? pretty = null) | ||||
|             : base(message, ex, pretty) | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         internal static CommandConfigurationException NoCommandConfigured() | ||||
|         { | ||||
|             return new CommandConfigurationException("No commands have been configured."); | ||||
|         } | ||||
|  | ||||
|         internal static CommandConfigurationException CommandNameConflict(CommandInfo command, string alias) | ||||
|         { | ||||
|             return new CommandConfigurationException($"The alias '{alias}' for '{command.Name}' conflicts with another command."); | ||||
|         } | ||||
|  | ||||
|         internal static CommandConfigurationException DuplicateOption(CommandInfo command, string[] options) | ||||
|         { | ||||
|             var keys = string.Join(", ", options.Select(x => x.Length > 1 ? $"--{x}" : $"-{x}")); | ||||
|             if (options.Length > 1) | ||||
|             { | ||||
|                 return new CommandConfigurationException($"Options {keys} are duplicated in command '{command.Name}'."); | ||||
|             } | ||||
|  | ||||
|             return new CommandConfigurationException($"Option {keys} is duplicated in command '{command.Name}'."); | ||||
|         } | ||||
|  | ||||
|         internal static CommandConfigurationException BranchHasNoChildren(CommandInfo command) | ||||
|         { | ||||
|             throw new CommandConfigurationException($"The branch '{command.Name}' does not define any commands."); | ||||
|         } | ||||
|  | ||||
|         internal static CommandConfigurationException TooManyVectorArguments(CommandInfo command) | ||||
|         { | ||||
|             throw new CommandConfigurationException($"The command '{command.Name}' specifies more than one vector argument."); | ||||
|         } | ||||
|  | ||||
|         internal static CommandConfigurationException VectorArgumentNotSpecifiedLast(CommandInfo command) | ||||
|         { | ||||
|             throw new CommandConfigurationException($"The command '{command.Name}' specifies an argument vector that is not the last argument."); | ||||
|         } | ||||
|  | ||||
|         internal static CommandConfigurationException OptionalOptionValueMustBeFlagWithValue(CommandOption option) | ||||
|         { | ||||
|             return new CommandConfigurationException($"The option '{option.GetOptionName()}' has an optional value but does not implement IFlagValue."); | ||||
|         } | ||||
|  | ||||
|         internal static CommandConfigurationException OptionBothHasPairDeconstructorAndTypeParameter(CommandOption option) | ||||
|         { | ||||
|             return new CommandConfigurationException($"The option '{option.GetOptionName()}' is both marked as pair deconstructable and convertable."); | ||||
|         } | ||||
|  | ||||
|         internal static CommandConfigurationException OptionTypeDoesNotSupportDeconstruction(CommandOption option) | ||||
|         { | ||||
|             return new CommandConfigurationException($"The option '{option.GetOptionName()}' is marked as " + | ||||
|                 "pair deconstructable, but the underlying type does not support that."); | ||||
|         } | ||||
|  | ||||
|         internal static CommandConfigurationException RequiredArgumentsCannotHaveDefaultValue(CommandArgument option) | ||||
|         { | ||||
|             return new CommandConfigurationException($"The required argument '{option.Value}' cannot have a default value."); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
|     internal CommandConfigurationException(string message, Exception ex, IRenderable? pretty = null) | ||||
|         : base(message, ex, pretty) | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     internal static CommandConfigurationException NoCommandConfigured() | ||||
|     { | ||||
|         return new CommandConfigurationException("No commands have been configured."); | ||||
|     } | ||||
|  | ||||
|     internal static CommandConfigurationException CommandNameConflict(CommandInfo command, string alias) | ||||
|     { | ||||
|         return new CommandConfigurationException($"The alias '{alias}' for '{command.Name}' conflicts with another command."); | ||||
|     } | ||||
|  | ||||
|     internal static CommandConfigurationException DuplicateOption(CommandInfo command, string[] options) | ||||
|     { | ||||
|         var keys = string.Join(", ", options.Select(x => x.Length > 1 ? $"--{x}" : $"-{x}")); | ||||
|         if (options.Length > 1) | ||||
|         { | ||||
|             return new CommandConfigurationException($"Options {keys} are duplicated in command '{command.Name}'."); | ||||
|         } | ||||
|  | ||||
|         return new CommandConfigurationException($"Option {keys} is duplicated in command '{command.Name}'."); | ||||
|     } | ||||
|  | ||||
|     internal static CommandConfigurationException BranchHasNoChildren(CommandInfo command) | ||||
|     { | ||||
|         throw new CommandConfigurationException($"The branch '{command.Name}' does not define any commands."); | ||||
|     } | ||||
|  | ||||
|     internal static CommandConfigurationException TooManyVectorArguments(CommandInfo command) | ||||
|     { | ||||
|         throw new CommandConfigurationException($"The command '{command.Name}' specifies more than one vector argument."); | ||||
|     } | ||||
|  | ||||
|     internal static CommandConfigurationException VectorArgumentNotSpecifiedLast(CommandInfo command) | ||||
|     { | ||||
|         throw new CommandConfigurationException($"The command '{command.Name}' specifies an argument vector that is not the last argument."); | ||||
|     } | ||||
|  | ||||
|     internal static CommandConfigurationException OptionalOptionValueMustBeFlagWithValue(CommandOption option) | ||||
|     { | ||||
|         return new CommandConfigurationException($"The option '{option.GetOptionName()}' has an optional value but does not implement IFlagValue."); | ||||
|     } | ||||
|  | ||||
|     internal static CommandConfigurationException OptionBothHasPairDeconstructorAndTypeParameter(CommandOption option) | ||||
|     { | ||||
|         return new CommandConfigurationException($"The option '{option.GetOptionName()}' is both marked as pair deconstructable and convertable."); | ||||
|     } | ||||
|  | ||||
|     internal static CommandConfigurationException OptionTypeDoesNotSupportDeconstruction(CommandOption option) | ||||
|     { | ||||
|         return new CommandConfigurationException($"The option '{option.GetOptionName()}' is marked as " + | ||||
|             "pair deconstructable, but the underlying type does not support that."); | ||||
|     } | ||||
|  | ||||
|     internal static CommandConfigurationException RequiredArgumentsCannotHaveDefaultValue(CommandArgument option) | ||||
|     { | ||||
|         return new CommandConfigurationException($"The required argument '{option.Value}' cannot have a default value."); | ||||
|     } | ||||
| } | ||||
| @@ -1,45 +1,44 @@ | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| /// <summary> | ||||
| /// Represents a command context. | ||||
| /// </summary> | ||||
| public sealed class CommandContext | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Represents a command context. | ||||
|     /// Gets the remaining arguments. | ||||
|     /// </summary> | ||||
|     public sealed class CommandContext | ||||
|     /// <value> | ||||
|     /// The remaining arguments. | ||||
|     /// </value> | ||||
|     public IRemainingArguments Remaining { get; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Gets the name of the command. | ||||
|     /// </summary> | ||||
|     /// <value> | ||||
|     /// The name of the command. | ||||
|     /// </value> | ||||
|     public string Name { get; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Gets the data that was passed to the command during registration (if any). | ||||
|     /// </summary> | ||||
|     /// <value> | ||||
|     /// The command data. | ||||
|     /// </value> | ||||
|     public object? Data { get; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Initializes a new instance of the <see cref="CommandContext"/> class. | ||||
|     /// </summary> | ||||
|     /// <param name="remaining">The remaining arguments.</param> | ||||
|     /// <param name="name">The command name.</param> | ||||
|     /// <param name="data">The command data.</param> | ||||
|     public CommandContext(IRemainingArguments remaining, string name, object? data) | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Gets the remaining arguments. | ||||
|         /// </summary> | ||||
|         /// <value> | ||||
|         /// The remaining arguments. | ||||
|         /// </value> | ||||
|         public IRemainingArguments Remaining { get; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets the name of the command. | ||||
|         /// </summary> | ||||
|         /// <value> | ||||
|         /// The name of the command. | ||||
|         /// </value> | ||||
|         public string Name { get; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets the data that was passed to the command during registration (if any). | ||||
|         /// </summary> | ||||
|         /// <value> | ||||
|         /// The command data. | ||||
|         /// </value> | ||||
|         public object? Data { get; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Initializes a new instance of the <see cref="CommandContext"/> class. | ||||
|         /// </summary> | ||||
|         /// <param name="remaining">The remaining arguments.</param> | ||||
|         /// <param name="name">The command name.</param> | ||||
|         /// <param name="data">The command data.</param> | ||||
|         public CommandContext(IRemainingArguments remaining, string name, object? data) | ||||
|         { | ||||
|             Remaining = remaining ?? throw new System.ArgumentNullException(nameof(remaining)); | ||||
|             Name = name ?? throw new System.ArgumentNullException(nameof(name)); | ||||
|             Data = data; | ||||
|         } | ||||
|         Remaining = remaining ?? throw new System.ArgumentNullException(nameof(remaining)); | ||||
|         Name = name ?? throw new System.ArgumentNullException(nameof(name)); | ||||
|         Data = data; | ||||
|     } | ||||
| } | ||||
| } | ||||
| @@ -2,52 +2,51 @@ using System.Diagnostics; | ||||
| using System.Diagnostics.CodeAnalysis; | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| /// <summary> | ||||
| /// Base class for a command. | ||||
| /// </summary> | ||||
| /// <typeparam name="TSettings">The settings type.</typeparam> | ||||
| /// <seealso cref="AsyncCommand{TSettings}"/> | ||||
| public abstract class Command<TSettings> : ICommand<TSettings> | ||||
|     where TSettings : CommandSettings | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Base class for a command. | ||||
|     /// Validates the specified settings and remaining arguments. | ||||
|     /// </summary> | ||||
|     /// <typeparam name="TSettings">The settings type.</typeparam> | ||||
|     /// <seealso cref="AsyncCommand{TSettings}"/> | ||||
|     public abstract class Command<TSettings> : ICommand<TSettings> | ||||
|         where TSettings : CommandSettings | ||||
|     /// <param name="context">The command context.</param> | ||||
|     /// <param name="settings">The settings.</param> | ||||
|     /// <returns>The validation result.</returns> | ||||
|     public virtual ValidationResult Validate([NotNull] CommandContext context, [NotNull] TSettings settings) | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Validates the specified settings and remaining arguments. | ||||
|         /// </summary> | ||||
|         /// <param name="context">The command context.</param> | ||||
|         /// <param name="settings">The settings.</param> | ||||
|         /// <returns>The validation result.</returns> | ||||
|         public virtual ValidationResult Validate([NotNull] CommandContext context, [NotNull] TSettings settings) | ||||
|         { | ||||
|             return ValidationResult.Success(); | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Executes the command. | ||||
|         /// </summary> | ||||
|         /// <param name="context">The command context.</param> | ||||
|         /// <param name="settings">The settings.</param> | ||||
|         /// <returns>An integer indicating whether or not the command executed successfully.</returns> | ||||
|         public abstract int Execute([NotNull] CommandContext context, [NotNull] TSettings settings); | ||||
|  | ||||
|         /// <inheritdoc/> | ||||
|         ValidationResult ICommand.Validate(CommandContext context, CommandSettings settings) | ||||
|         { | ||||
|             return Validate(context, (TSettings)settings); | ||||
|         } | ||||
|  | ||||
|         /// <inheritdoc/> | ||||
|         Task<int> ICommand.Execute(CommandContext context, CommandSettings settings) | ||||
|         { | ||||
|             Debug.Assert(settings is TSettings, "Command settings is of unexpected type."); | ||||
|             return Task.FromResult(Execute(context, (TSettings)settings)); | ||||
|         } | ||||
|  | ||||
|         /// <inheritdoc/> | ||||
|         Task<int> ICommand<TSettings>.Execute(CommandContext context, TSettings settings) | ||||
|         { | ||||
|             return Task.FromResult(Execute(context, settings)); | ||||
|         } | ||||
|         return ValidationResult.Success(); | ||||
|     } | ||||
| } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Executes the command. | ||||
|     /// </summary> | ||||
|     /// <param name="context">The command context.</param> | ||||
|     /// <param name="settings">The settings.</param> | ||||
|     /// <returns>An integer indicating whether or not the command executed successfully.</returns> | ||||
|     public abstract int Execute([NotNull] CommandContext context, [NotNull] TSettings settings); | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     ValidationResult ICommand.Validate(CommandContext context, CommandSettings settings) | ||||
|     { | ||||
|         return Validate(context, (TSettings)settings); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     Task<int> ICommand.Execute(CommandContext context, CommandSettings settings) | ||||
|     { | ||||
|         Debug.Assert(settings is TSettings, "Command settings is of unexpected type."); | ||||
|         return Task.FromResult(Execute(context, (TSettings)settings)); | ||||
|     } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     Task<int> ICommand<TSettings>.Execute(CommandContext context, TSettings settings) | ||||
|     { | ||||
|         return Task.FromResult(Execute(context, settings)); | ||||
|     } | ||||
| } | ||||
| @@ -1,38 +1,37 @@ | ||||
| using System; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| /// <summary> | ||||
| /// Represents a context for <see cref="ICommandParameterInfo"/> related operations. | ||||
| /// </summary> | ||||
| public sealed class CommandParameterContext | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Represents a context for <see cref="ICommandParameterInfo"/> related operations. | ||||
|     /// Gets the parameter. | ||||
|     /// </summary> | ||||
|     public sealed class CommandParameterContext | ||||
|     public ICommandParameterInfo Parameter { get; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Gets the type resolver. | ||||
|     /// </summary> | ||||
|     public ITypeResolver Resolver { get; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Gets tje parameter value. | ||||
|     /// </summary> | ||||
|     public object? Value { get; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Initializes a new instance of the <see cref="CommandParameterContext"/> class. | ||||
|     /// </summary> | ||||
|     /// <param name="parameter">The parameter.</param> | ||||
|     /// <param name="resolver">The type resolver.</param> | ||||
|     /// <param name="value">The parameter value.</param> | ||||
|     public CommandParameterContext(ICommandParameterInfo parameter, ITypeResolver resolver, object? value) | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Gets the parameter. | ||||
|         /// </summary> | ||||
|         public ICommandParameterInfo Parameter { get; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets the type resolver. | ||||
|         /// </summary> | ||||
|         public ITypeResolver Resolver { get; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets tje parameter value. | ||||
|         /// </summary> | ||||
|         public object? Value { get; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Initializes a new instance of the <see cref="CommandParameterContext"/> class. | ||||
|         /// </summary> | ||||
|         /// <param name="parameter">The parameter.</param> | ||||
|         /// <param name="resolver">The type resolver.</param> | ||||
|         /// <param name="value">The parameter value.</param> | ||||
|         public CommandParameterContext(ICommandParameterInfo parameter, ITypeResolver resolver, object? value) | ||||
|         { | ||||
|             Parameter = parameter ?? throw new ArgumentNullException(nameof(parameter)); | ||||
|             Resolver = resolver ?? throw new ArgumentNullException(nameof(resolver)); | ||||
|             Value = value; | ||||
|         } | ||||
|         Parameter = parameter ?? throw new ArgumentNullException(nameof(parameter)); | ||||
|         Resolver = resolver ?? throw new ArgumentNullException(nameof(resolver)); | ||||
|         Value = value; | ||||
|     } | ||||
| } | ||||
| } | ||||
| @@ -3,125 +3,124 @@ using System.Collections.Generic; | ||||
| using System.Globalization; | ||||
| using Spectre.Console.Rendering; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| /// <summary> | ||||
| /// Represents errors that occur during parsing. | ||||
| /// </summary> | ||||
| public sealed class CommandParseException : CommandRuntimeException | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Represents errors that occur during parsing. | ||||
|     /// </summary> | ||||
|     public sealed class CommandParseException : CommandRuntimeException | ||||
|     internal CommandParseException(string message, IRenderable? pretty = null) | ||||
|         : base(message, pretty) | ||||
|     { | ||||
|         internal CommandParseException(string message, IRenderable? pretty = null) | ||||
|             : base(message, pretty) | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         internal static CommandParseException CouldNotCreateSettings(Type settingsType) | ||||
|         { | ||||
|             return new CommandParseException($"Could not create settings of type '{settingsType.FullName}'."); | ||||
|         } | ||||
|  | ||||
|         internal static CommandParseException CouldNotCreateCommand(Type? commandType) | ||||
|         { | ||||
|             if (commandType == null) | ||||
|             { | ||||
|                 return new CommandParseException($"Could not create command. Command type is unknown."); | ||||
|             } | ||||
|  | ||||
|             return new CommandParseException($"Could not create command of type '{commandType.FullName}'."); | ||||
|         } | ||||
|  | ||||
|         internal static CommandParseException ExpectedTokenButFoundNull(CommandTreeToken.Kind expected) | ||||
|         { | ||||
|             return new CommandParseException($"Expected to find any token of type '{expected}' but found null instead."); | ||||
|         } | ||||
|  | ||||
|         internal static CommandParseException ExpectedTokenButFoundOther(CommandTreeToken.Kind expected, CommandTreeToken.Kind found) | ||||
|         { | ||||
|             return new CommandParseException($"Expected to find token of type '{expected}' but found '{found}' instead."); | ||||
|         } | ||||
|  | ||||
|         internal static CommandParseException OptionHasNoName(string input, CommandTreeToken token) | ||||
|         { | ||||
|             return CommandLineParseExceptionFactory.Create(input, token, "Option does not have a name.", "Did you forget the option name?"); | ||||
|         } | ||||
|  | ||||
|         internal static CommandParseException OptionValueWasExpected(string input, CommandTreeToken token) | ||||
|         { | ||||
|             return CommandLineParseExceptionFactory.Create(input, token, "Expected an option value.", "Did you forget the option value?"); | ||||
|         } | ||||
|  | ||||
|         internal static CommandParseException OptionHasNoValue(IEnumerable<string> args, CommandTreeToken token, CommandOption option) | ||||
|         { | ||||
|             return CommandLineParseExceptionFactory.Create(args, token, $"Option '{option.GetOptionName()}' is defined but no value has been provided.", "No value provided."); | ||||
|         } | ||||
|  | ||||
|         internal static CommandParseException UnexpectedOption(IEnumerable<string> args, CommandTreeToken token) | ||||
|         { | ||||
|             return CommandLineParseExceptionFactory.Create(args, token, $"Unexpected option '{token.Value}'.", "Did you forget the command?"); | ||||
|         } | ||||
|  | ||||
|         internal static CommandParseException CannotAssignValueToFlag(IEnumerable<string> args, CommandTreeToken token) | ||||
|         { | ||||
|             return CommandLineParseExceptionFactory.Create(args, token, "Flags cannot be assigned a value.", "Can't assign value."); | ||||
|         } | ||||
|  | ||||
|         internal static CommandParseException InvalidShortOptionName(string input, CommandTreeToken token) | ||||
|         { | ||||
|             return CommandLineParseExceptionFactory.Create(input, token, "Short option does not have a valid name.", "Not a valid name for a short option."); | ||||
|         } | ||||
|  | ||||
|         internal static CommandParseException LongOptionNameIsMissing(TextBuffer reader, int position) | ||||
|         { | ||||
|             var token = new CommandTreeToken(CommandTreeToken.Kind.LongOption, position, string.Empty, "--"); | ||||
|             return CommandLineParseExceptionFactory.Create(reader.Original, token, "Invalid long option name.", "Did you forget the option name?"); | ||||
|         } | ||||
|  | ||||
|         internal static CommandParseException LongOptionNameIsOneCharacter(TextBuffer reader, int position, string name) | ||||
|         { | ||||
|             var token = new CommandTreeToken(CommandTreeToken.Kind.LongOption, position, name, $"--{name}"); | ||||
|             var reason = $"Did you mean -{name}?"; | ||||
|             return CommandLineParseExceptionFactory.Create(reader.Original, token, "Invalid long option name.", reason); | ||||
|         } | ||||
|  | ||||
|         internal static CommandParseException LongOptionNameStartWithDigit(TextBuffer reader, int position, string name) | ||||
|         { | ||||
|             var token = new CommandTreeToken(CommandTreeToken.Kind.LongOption, position, name, $"--{name}"); | ||||
|             return CommandLineParseExceptionFactory.Create(reader.Original, token, "Invalid long option name.", "Option names cannot start with a digit."); | ||||
|         } | ||||
|  | ||||
|         internal static CommandParseException LongOptionNameContainSymbol(TextBuffer reader, int position, char character) | ||||
|         { | ||||
|             var name = character.ToString(CultureInfo.InvariantCulture); | ||||
|             var token = new CommandTreeToken(CommandTreeToken.Kind.LongOption, position, name, name); | ||||
|             return CommandLineParseExceptionFactory.Create(reader.Original, token, "Invalid long option name.", "Invalid character."); | ||||
|         } | ||||
|  | ||||
|         internal static CommandParseException UnterminatedQuote(string input, CommandTreeToken token) | ||||
|         { | ||||
|             return CommandLineParseExceptionFactory.Create(input, token, $"Encountered unterminated quoted string '{token.Value}'.", "Did you forget the closing quotation mark?"); | ||||
|         } | ||||
|  | ||||
|         internal static CommandParseException UnknownCommand(CommandModel model, CommandTree? node, IEnumerable<string> args, CommandTreeToken token) | ||||
|         { | ||||
|             var suggestion = CommandSuggestor.Suggest(model, node?.Command, token.Value); | ||||
|             var text = suggestion != null ? $"Did you mean '{suggestion.Name}'?" : "No such command."; | ||||
|             return CommandLineParseExceptionFactory.Create(args, token, $"Unknown command '{token.Value}'.", text); | ||||
|         } | ||||
|  | ||||
|         internal static CommandParseException CouldNotMatchArgument(IEnumerable<string> args, CommandTreeToken token) | ||||
|         { | ||||
|             return CommandLineParseExceptionFactory.Create(args, token, $"Could not match '{token.Value}' with an argument.", "Could not match to argument."); | ||||
|         } | ||||
|  | ||||
|         internal static CommandParseException UnknownOption(IEnumerable<string> args, CommandTreeToken token) | ||||
|         { | ||||
|             return CommandLineParseExceptionFactory.Create(args, token, $"Unknown option '{token.Value}'.", "Unknown option."); | ||||
|         } | ||||
|  | ||||
|         internal static CommandParseException ValueIsNotInValidFormat(string value) | ||||
|         { | ||||
|             var text = $"[red]Error:[/] The value '[white]{value}[/]' is not in a correct format"; | ||||
|             return new CommandParseException("Could not parse value", new Markup(text)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
|     internal static CommandParseException CouldNotCreateSettings(Type settingsType) | ||||
|     { | ||||
|         return new CommandParseException($"Could not create settings of type '{settingsType.FullName}'."); | ||||
|     } | ||||
|  | ||||
|     internal static CommandParseException CouldNotCreateCommand(Type? commandType) | ||||
|     { | ||||
|         if (commandType == null) | ||||
|         { | ||||
|             return new CommandParseException($"Could not create command. Command type is unknown."); | ||||
|         } | ||||
|  | ||||
|         return new CommandParseException($"Could not create command of type '{commandType.FullName}'."); | ||||
|     } | ||||
|  | ||||
|     internal static CommandParseException ExpectedTokenButFoundNull(CommandTreeToken.Kind expected) | ||||
|     { | ||||
|         return new CommandParseException($"Expected to find any token of type '{expected}' but found null instead."); | ||||
|     } | ||||
|  | ||||
|     internal static CommandParseException ExpectedTokenButFoundOther(CommandTreeToken.Kind expected, CommandTreeToken.Kind found) | ||||
|     { | ||||
|         return new CommandParseException($"Expected to find token of type '{expected}' but found '{found}' instead."); | ||||
|     } | ||||
|  | ||||
|     internal static CommandParseException OptionHasNoName(string input, CommandTreeToken token) | ||||
|     { | ||||
|         return CommandLineParseExceptionFactory.Create(input, token, "Option does not have a name.", "Did you forget the option name?"); | ||||
|     } | ||||
|  | ||||
|     internal static CommandParseException OptionValueWasExpected(string input, CommandTreeToken token) | ||||
|     { | ||||
|         return CommandLineParseExceptionFactory.Create(input, token, "Expected an option value.", "Did you forget the option value?"); | ||||
|     } | ||||
|  | ||||
|     internal static CommandParseException OptionHasNoValue(IEnumerable<string> args, CommandTreeToken token, CommandOption option) | ||||
|     { | ||||
|         return CommandLineParseExceptionFactory.Create(args, token, $"Option '{option.GetOptionName()}' is defined but no value has been provided.", "No value provided."); | ||||
|     } | ||||
|  | ||||
|     internal static CommandParseException UnexpectedOption(IEnumerable<string> args, CommandTreeToken token) | ||||
|     { | ||||
|         return CommandLineParseExceptionFactory.Create(args, token, $"Unexpected option '{token.Value}'.", "Did you forget the command?"); | ||||
|     } | ||||
|  | ||||
|     internal static CommandParseException CannotAssignValueToFlag(IEnumerable<string> args, CommandTreeToken token) | ||||
|     { | ||||
|         return CommandLineParseExceptionFactory.Create(args, token, "Flags cannot be assigned a value.", "Can't assign value."); | ||||
|     } | ||||
|  | ||||
|     internal static CommandParseException InvalidShortOptionName(string input, CommandTreeToken token) | ||||
|     { | ||||
|         return CommandLineParseExceptionFactory.Create(input, token, "Short option does not have a valid name.", "Not a valid name for a short option."); | ||||
|     } | ||||
|  | ||||
|     internal static CommandParseException LongOptionNameIsMissing(TextBuffer reader, int position) | ||||
|     { | ||||
|         var token = new CommandTreeToken(CommandTreeToken.Kind.LongOption, position, string.Empty, "--"); | ||||
|         return CommandLineParseExceptionFactory.Create(reader.Original, token, "Invalid long option name.", "Did you forget the option name?"); | ||||
|     } | ||||
|  | ||||
|     internal static CommandParseException LongOptionNameIsOneCharacter(TextBuffer reader, int position, string name) | ||||
|     { | ||||
|         var token = new CommandTreeToken(CommandTreeToken.Kind.LongOption, position, name, $"--{name}"); | ||||
|         var reason = $"Did you mean -{name}?"; | ||||
|         return CommandLineParseExceptionFactory.Create(reader.Original, token, "Invalid long option name.", reason); | ||||
|     } | ||||
|  | ||||
|     internal static CommandParseException LongOptionNameStartWithDigit(TextBuffer reader, int position, string name) | ||||
|     { | ||||
|         var token = new CommandTreeToken(CommandTreeToken.Kind.LongOption, position, name, $"--{name}"); | ||||
|         return CommandLineParseExceptionFactory.Create(reader.Original, token, "Invalid long option name.", "Option names cannot start with a digit."); | ||||
|     } | ||||
|  | ||||
|     internal static CommandParseException LongOptionNameContainSymbol(TextBuffer reader, int position, char character) | ||||
|     { | ||||
|         var name = character.ToString(CultureInfo.InvariantCulture); | ||||
|         var token = new CommandTreeToken(CommandTreeToken.Kind.LongOption, position, name, name); | ||||
|         return CommandLineParseExceptionFactory.Create(reader.Original, token, "Invalid long option name.", "Invalid character."); | ||||
|     } | ||||
|  | ||||
|     internal static CommandParseException UnterminatedQuote(string input, CommandTreeToken token) | ||||
|     { | ||||
|         return CommandLineParseExceptionFactory.Create(input, token, $"Encountered unterminated quoted string '{token.Value}'.", "Did you forget the closing quotation mark?"); | ||||
|     } | ||||
|  | ||||
|     internal static CommandParseException UnknownCommand(CommandModel model, CommandTree? node, IEnumerable<string> args, CommandTreeToken token) | ||||
|     { | ||||
|         var suggestion = CommandSuggestor.Suggest(model, node?.Command, token.Value); | ||||
|         var text = suggestion != null ? $"Did you mean '{suggestion.Name}'?" : "No such command."; | ||||
|         return CommandLineParseExceptionFactory.Create(args, token, $"Unknown command '{token.Value}'.", text); | ||||
|     } | ||||
|  | ||||
|     internal static CommandParseException CouldNotMatchArgument(IEnumerable<string> args, CommandTreeToken token) | ||||
|     { | ||||
|         return CommandLineParseExceptionFactory.Create(args, token, $"Could not match '{token.Value}' with an argument.", "Could not match to argument."); | ||||
|     } | ||||
|  | ||||
|     internal static CommandParseException UnknownOption(IEnumerable<string> args, CommandTreeToken token) | ||||
|     { | ||||
|         return CommandLineParseExceptionFactory.Create(args, token, $"Unknown option '{token.Value}'.", "Unknown option."); | ||||
|     } | ||||
|  | ||||
|     internal static CommandParseException ValueIsNotInValidFormat(string value) | ||||
|     { | ||||
|         var text = $"[red]Error:[/] The value '[white]{value}[/]' is not in a correct format"; | ||||
|         return new CommandParseException("Could not parse value", new Markup(text)); | ||||
|     } | ||||
| } | ||||
| @@ -1,58 +1,57 @@ | ||||
| using System; | ||||
| using Spectre.Console.Rendering; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| /// <summary> | ||||
| /// Represents errors that occur during runtime. | ||||
| /// </summary> | ||||
| public class CommandRuntimeException : CommandAppException | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Represents errors that occur during runtime. | ||||
|     /// </summary> | ||||
|     public class CommandRuntimeException : CommandAppException | ||||
|     internal CommandRuntimeException(string message, IRenderable? pretty = null) | ||||
|         : base(message, pretty) | ||||
|     { | ||||
|         internal CommandRuntimeException(string message, IRenderable? pretty = null) | ||||
|             : base(message, pretty) | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         internal CommandRuntimeException(string message, Exception ex, IRenderable? pretty = null) | ||||
|             : base(message, ex, pretty) | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         internal static CommandRuntimeException CouldNotResolveType(Type type, Exception? ex = null) | ||||
|         { | ||||
|             var message = $"Could not resolve type '{type.FullName}'."; | ||||
|             if (ex != null) | ||||
|             { | ||||
|                 // TODO: Show internal stuff here. | ||||
|                 return new CommandRuntimeException(message, ex); | ||||
|             } | ||||
|  | ||||
|             return new CommandRuntimeException(message); | ||||
|         } | ||||
|  | ||||
|         internal static CommandRuntimeException MissingRequiredArgument(CommandTree node, CommandArgument argument) | ||||
|         { | ||||
|             if (node.Command.Name == CliConstants.DefaultCommandName) | ||||
|             { | ||||
|                 return new CommandRuntimeException($"Missing required argument '{argument.Value}'."); | ||||
|             } | ||||
|  | ||||
|             return new CommandRuntimeException($"Command '{node.Command.Name}' is missing required argument '{argument.Value}'."); | ||||
|         } | ||||
|  | ||||
|         internal static CommandRuntimeException NoConverterFound(CommandParameter parameter) | ||||
|         { | ||||
|             return new CommandRuntimeException($"Could not find converter for type '{parameter.ParameterType.FullName}'."); | ||||
|         } | ||||
|  | ||||
|         internal static CommandRuntimeException ValidationFailed(ValidationResult result) | ||||
|         { | ||||
|             return new CommandRuntimeException(result.Message ?? "Unknown validation error."); | ||||
|         } | ||||
|  | ||||
|         internal static Exception CouldNotGetSettingsType(Type commandType) | ||||
|         { | ||||
|             return new CommandRuntimeException($"Could not get settings type for command of type '{commandType.FullName}'."); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
|     internal CommandRuntimeException(string message, Exception ex, IRenderable? pretty = null) | ||||
|         : base(message, ex, pretty) | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     internal static CommandRuntimeException CouldNotResolveType(Type type, Exception? ex = null) | ||||
|     { | ||||
|         var message = $"Could not resolve type '{type.FullName}'."; | ||||
|         if (ex != null) | ||||
|         { | ||||
|             // TODO: Show internal stuff here. | ||||
|             return new CommandRuntimeException(message, ex); | ||||
|         } | ||||
|  | ||||
|         return new CommandRuntimeException(message); | ||||
|     } | ||||
|  | ||||
|     internal static CommandRuntimeException MissingRequiredArgument(CommandTree node, CommandArgument argument) | ||||
|     { | ||||
|         if (node.Command.Name == CliConstants.DefaultCommandName) | ||||
|         { | ||||
|             return new CommandRuntimeException($"Missing required argument '{argument.Value}'."); | ||||
|         } | ||||
|  | ||||
|         return new CommandRuntimeException($"Command '{node.Command.Name}' is missing required argument '{argument.Value}'."); | ||||
|     } | ||||
|  | ||||
|     internal static CommandRuntimeException NoConverterFound(CommandParameter parameter) | ||||
|     { | ||||
|         return new CommandRuntimeException($"Could not find converter for type '{parameter.ParameterType.FullName}'."); | ||||
|     } | ||||
|  | ||||
|     internal static CommandRuntimeException ValidationFailed(ValidationResult result) | ||||
|     { | ||||
|         return new CommandRuntimeException(result.Message ?? "Unknown validation error."); | ||||
|     } | ||||
|  | ||||
|     internal static Exception CouldNotGetSettingsType(Type commandType) | ||||
|     { | ||||
|         return new CommandRuntimeException($"Could not get settings type for command of type '{commandType.FullName}'."); | ||||
|     } | ||||
| } | ||||
| @@ -1,17 +1,16 @@ | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| /// <summary> | ||||
| /// Base class for command settings. | ||||
| /// </summary> | ||||
| public abstract class CommandSettings | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Base class for command settings. | ||||
|     /// Performs validation of the settings. | ||||
|     /// </summary> | ||||
|     public abstract class CommandSettings | ||||
|     /// <returns>The validation result.</returns> | ||||
|     public virtual ValidationResult Validate() | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Performs validation of the settings. | ||||
|         /// </summary> | ||||
|         /// <returns>The validation result.</returns> | ||||
|         public virtual ValidationResult Validate() | ||||
|         { | ||||
|             return ValidationResult.Success(); | ||||
|         } | ||||
|         return ValidationResult.Success(); | ||||
|     } | ||||
| } | ||||
| } | ||||
| @@ -1,160 +1,159 @@ | ||||
| using System.Globalization; | ||||
| using Spectre.Console.Rendering; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| /// <summary> | ||||
| /// Represents errors related to parameter templates. | ||||
| /// </summary> | ||||
| public sealed class CommandTemplateException : CommandConfigurationException | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Represents errors related to parameter templates. | ||||
|     /// Gets the template that contains the error. | ||||
|     /// </summary> | ||||
|     public sealed class CommandTemplateException : CommandConfigurationException | ||||
|     public string Template { get; } | ||||
|  | ||||
|     internal override bool AlwaysPropagateWhenDebugging => true; | ||||
|  | ||||
|     internal CommandTemplateException(string message, string template, IRenderable pretty) | ||||
|         : base(message, pretty) | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Gets the template that contains the error. | ||||
|         /// </summary> | ||||
|         public string Template { get; } | ||||
|  | ||||
|         internal override bool AlwaysPropagateWhenDebugging => true; | ||||
|  | ||||
|         internal CommandTemplateException(string message, string template, IRenderable pretty) | ||||
|             : base(message, pretty) | ||||
|         { | ||||
|             Template = template; | ||||
|         } | ||||
|  | ||||
|         internal static CommandTemplateException UnexpectedCharacter(string template, int position, char character) | ||||
|         { | ||||
|             return CommandLineTemplateExceptionFactory.Create( | ||||
|                 template, | ||||
|                 new TemplateToken(TemplateToken.Kind.Unknown, position, $"{character}", $"{character}"), | ||||
|                 $"Encountered unexpected character '{character}'.", | ||||
|                 "Unexpected character."); | ||||
|         } | ||||
|  | ||||
|         internal static CommandTemplateException UnterminatedValueName(string template, TemplateToken token) | ||||
|         { | ||||
|             return CommandLineTemplateExceptionFactory.Create( | ||||
|                 template, token, | ||||
|                 $"Encountered unterminated value name '{token.Value}'.", | ||||
|                 "Unterminated value name."); | ||||
|         } | ||||
|  | ||||
|         internal static CommandTemplateException ArgumentCannotContainOptions(string template, TemplateToken token) | ||||
|         { | ||||
|             return CommandLineTemplateExceptionFactory.Create( | ||||
|                 template, token, | ||||
|                 "Arguments can not contain options.", | ||||
|                 "Not permitted."); | ||||
|         } | ||||
|  | ||||
|         internal static CommandTemplateException MultipleValuesAreNotSupported(string template, TemplateToken token) | ||||
|         { | ||||
|             return CommandLineTemplateExceptionFactory.Create(template, token, | ||||
|                 "Multiple values are not supported.", | ||||
|                 "Too many values."); | ||||
|         } | ||||
|  | ||||
|         internal static CommandTemplateException ValuesMustHaveName(string template, TemplateToken token) | ||||
|         { | ||||
|             return CommandLineTemplateExceptionFactory.Create(template, token, | ||||
|                 "Values without name are not allowed.", | ||||
|                 "Missing value name."); | ||||
|         } | ||||
|  | ||||
|         internal static CommandTemplateException OptionsMustHaveName(string template, TemplateToken token) | ||||
|         { | ||||
|             return CommandLineTemplateExceptionFactory.Create(template, token, | ||||
|                 "Options without name are not allowed.", | ||||
|                 "Missing option name."); | ||||
|         } | ||||
|  | ||||
|         internal static CommandTemplateException OptionNamesCannotStartWithDigit(string template, TemplateToken token) | ||||
|         { | ||||
|             // Rewrite the token to point to the option name instead of the whole string. | ||||
|             token = new TemplateToken( | ||||
|                 token.TokenKind, | ||||
|                 token.TokenKind == TemplateToken.Kind.ShortName ? token.Position + 1 : token.Position + 2, | ||||
|                 token.Value, token.Value); | ||||
|  | ||||
|             return CommandLineTemplateExceptionFactory.Create(template, token, | ||||
|                 "Option names cannot start with a digit.", | ||||
|                 "Invalid option name."); | ||||
|         } | ||||
|  | ||||
|         internal static CommandTemplateException InvalidCharacterInOptionName(string template, TemplateToken token, char character) | ||||
|         { | ||||
|             // Rewrite the token to point to the invalid character instead of the whole value. | ||||
|             var position = (token.TokenKind == TemplateToken.Kind.ShortName | ||||
|                 ? token.Position + 1 | ||||
|                 : token.Position + 2) + token.Value.OrdinalIndexOf(character); | ||||
|  | ||||
|             token = new TemplateToken( | ||||
|                 token.TokenKind, position, | ||||
|                 token.Value, character.ToString(CultureInfo.InvariantCulture)); | ||||
|  | ||||
|             return CommandLineTemplateExceptionFactory.Create(template, token, | ||||
|                 $"Encountered invalid character '{character}' in option name.", | ||||
|                 "Invalid character."); | ||||
|         } | ||||
|  | ||||
|         internal static CommandTemplateException LongOptionMustHaveMoreThanOneCharacter(string template, TemplateToken token) | ||||
|         { | ||||
|             // Rewrite the token to point to the option name instead of the whole option. | ||||
|             token = new TemplateToken(token.TokenKind, token.Position + 2, token.Value, token.Value); | ||||
|  | ||||
|             return CommandLineTemplateExceptionFactory.Create(template, token, | ||||
|                 "Long option names must consist of more than one character.", | ||||
|                 "Invalid option name."); | ||||
|         } | ||||
|  | ||||
|         internal static CommandTemplateException MultipleShortOptionNamesNotAllowed(string template, TemplateToken token) | ||||
|         { | ||||
|             return CommandLineTemplateExceptionFactory.Create(template, token, | ||||
|                 "Multiple short option names are not supported.", | ||||
|                 "Too many short options."); | ||||
|         } | ||||
|  | ||||
|         internal static CommandTemplateException ShortOptionMustOnlyBeOneCharacter(string template, TemplateToken token) | ||||
|         { | ||||
|             // Rewrite the token to point to the option name instead of the whole option. | ||||
|             token = new TemplateToken(token.TokenKind, token.Position + 1, token.Value, token.Value); | ||||
|  | ||||
|             return CommandLineTemplateExceptionFactory.Create(template, token, | ||||
|                 "Short option names can not be longer than one character.", | ||||
|                 "Invalid option name."); | ||||
|         } | ||||
|  | ||||
|         internal static CommandTemplateException MultipleOptionValuesAreNotSupported(string template, TemplateToken token) | ||||
|         { | ||||
|             return CommandLineTemplateExceptionFactory.Create(template, token, | ||||
|                 "Multiple option values are not supported.", | ||||
|                 "Too many option values."); | ||||
|         } | ||||
|  | ||||
|         internal static CommandTemplateException InvalidCharacterInValueName(string template, TemplateToken token, char character) | ||||
|         { | ||||
|             // Rewrite the token to point to the invalid character instead of the whole value. | ||||
|             token = new TemplateToken( | ||||
|                 token.TokenKind, | ||||
|                 token.Position + 1 + token.Value.OrdinalIndexOf(character), | ||||
|                 token.Value, character.ToString(CultureInfo.InvariantCulture)); | ||||
|  | ||||
|             return CommandLineTemplateExceptionFactory.Create(template, token, | ||||
|                 $"Encountered invalid character '{character}' in value name.", | ||||
|                 "Invalid character."); | ||||
|         } | ||||
|  | ||||
|         internal static CommandTemplateException MissingLongAndShortName(string template, TemplateToken? token) | ||||
|         { | ||||
|             return CommandLineTemplateExceptionFactory.Create(template, token, | ||||
|                 "No long or short name for option has been specified.", | ||||
|                 "Missing option. Was this meant to be an argument?"); | ||||
|         } | ||||
|  | ||||
|         internal static CommandTemplateException ArgumentsMustHaveValueName(string template) | ||||
|         { | ||||
|             return CommandLineTemplateExceptionFactory.Create(template, null, | ||||
|                 "Arguments must have a value name.", | ||||
|                 "Missing value name."); | ||||
|         } | ||||
|         Template = template; | ||||
|     } | ||||
| } | ||||
|  | ||||
|     internal static CommandTemplateException UnexpectedCharacter(string template, int position, char character) | ||||
|     { | ||||
|         return CommandLineTemplateExceptionFactory.Create( | ||||
|             template, | ||||
|             new TemplateToken(TemplateToken.Kind.Unknown, position, $"{character}", $"{character}"), | ||||
|             $"Encountered unexpected character '{character}'.", | ||||
|             "Unexpected character."); | ||||
|     } | ||||
|  | ||||
|     internal static CommandTemplateException UnterminatedValueName(string template, TemplateToken token) | ||||
|     { | ||||
|         return CommandLineTemplateExceptionFactory.Create( | ||||
|             template, token, | ||||
|             $"Encountered unterminated value name '{token.Value}'.", | ||||
|             "Unterminated value name."); | ||||
|     } | ||||
|  | ||||
|     internal static CommandTemplateException ArgumentCannotContainOptions(string template, TemplateToken token) | ||||
|     { | ||||
|         return CommandLineTemplateExceptionFactory.Create( | ||||
|             template, token, | ||||
|             "Arguments can not contain options.", | ||||
|             "Not permitted."); | ||||
|     } | ||||
|  | ||||
|     internal static CommandTemplateException MultipleValuesAreNotSupported(string template, TemplateToken token) | ||||
|     { | ||||
|         return CommandLineTemplateExceptionFactory.Create(template, token, | ||||
|             "Multiple values are not supported.", | ||||
|             "Too many values."); | ||||
|     } | ||||
|  | ||||
|     internal static CommandTemplateException ValuesMustHaveName(string template, TemplateToken token) | ||||
|     { | ||||
|         return CommandLineTemplateExceptionFactory.Create(template, token, | ||||
|             "Values without name are not allowed.", | ||||
|             "Missing value name."); | ||||
|     } | ||||
|  | ||||
|     internal static CommandTemplateException OptionsMustHaveName(string template, TemplateToken token) | ||||
|     { | ||||
|         return CommandLineTemplateExceptionFactory.Create(template, token, | ||||
|             "Options without name are not allowed.", | ||||
|             "Missing option name."); | ||||
|     } | ||||
|  | ||||
|     internal static CommandTemplateException OptionNamesCannotStartWithDigit(string template, TemplateToken token) | ||||
|     { | ||||
|         // Rewrite the token to point to the option name instead of the whole string. | ||||
|         token = new TemplateToken( | ||||
|             token.TokenKind, | ||||
|             token.TokenKind == TemplateToken.Kind.ShortName ? token.Position + 1 : token.Position + 2, | ||||
|             token.Value, token.Value); | ||||
|  | ||||
|         return CommandLineTemplateExceptionFactory.Create(template, token, | ||||
|             "Option names cannot start with a digit.", | ||||
|             "Invalid option name."); | ||||
|     } | ||||
|  | ||||
|     internal static CommandTemplateException InvalidCharacterInOptionName(string template, TemplateToken token, char character) | ||||
|     { | ||||
|         // Rewrite the token to point to the invalid character instead of the whole value. | ||||
|         var position = (token.TokenKind == TemplateToken.Kind.ShortName | ||||
|             ? token.Position + 1 | ||||
|             : token.Position + 2) + token.Value.OrdinalIndexOf(character); | ||||
|  | ||||
|         token = new TemplateToken( | ||||
|             token.TokenKind, position, | ||||
|             token.Value, character.ToString(CultureInfo.InvariantCulture)); | ||||
|  | ||||
|         return CommandLineTemplateExceptionFactory.Create(template, token, | ||||
|             $"Encountered invalid character '{character}' in option name.", | ||||
|             "Invalid character."); | ||||
|     } | ||||
|  | ||||
|     internal static CommandTemplateException LongOptionMustHaveMoreThanOneCharacter(string template, TemplateToken token) | ||||
|     { | ||||
|         // Rewrite the token to point to the option name instead of the whole option. | ||||
|         token = new TemplateToken(token.TokenKind, token.Position + 2, token.Value, token.Value); | ||||
|  | ||||
|         return CommandLineTemplateExceptionFactory.Create(template, token, | ||||
|             "Long option names must consist of more than one character.", | ||||
|             "Invalid option name."); | ||||
|     } | ||||
|  | ||||
|     internal static CommandTemplateException MultipleShortOptionNamesNotAllowed(string template, TemplateToken token) | ||||
|     { | ||||
|         return CommandLineTemplateExceptionFactory.Create(template, token, | ||||
|             "Multiple short option names are not supported.", | ||||
|             "Too many short options."); | ||||
|     } | ||||
|  | ||||
|     internal static CommandTemplateException ShortOptionMustOnlyBeOneCharacter(string template, TemplateToken token) | ||||
|     { | ||||
|         // Rewrite the token to point to the option name instead of the whole option. | ||||
|         token = new TemplateToken(token.TokenKind, token.Position + 1, token.Value, token.Value); | ||||
|  | ||||
|         return CommandLineTemplateExceptionFactory.Create(template, token, | ||||
|             "Short option names can not be longer than one character.", | ||||
|             "Invalid option name."); | ||||
|     } | ||||
|  | ||||
|     internal static CommandTemplateException MultipleOptionValuesAreNotSupported(string template, TemplateToken token) | ||||
|     { | ||||
|         return CommandLineTemplateExceptionFactory.Create(template, token, | ||||
|             "Multiple option values are not supported.", | ||||
|             "Too many option values."); | ||||
|     } | ||||
|  | ||||
|     internal static CommandTemplateException InvalidCharacterInValueName(string template, TemplateToken token, char character) | ||||
|     { | ||||
|         // Rewrite the token to point to the invalid character instead of the whole value. | ||||
|         token = new TemplateToken( | ||||
|             token.TokenKind, | ||||
|             token.Position + 1 + token.Value.OrdinalIndexOf(character), | ||||
|             token.Value, character.ToString(CultureInfo.InvariantCulture)); | ||||
|  | ||||
|         return CommandLineTemplateExceptionFactory.Create(template, token, | ||||
|             $"Encountered invalid character '{character}' in value name.", | ||||
|             "Invalid character."); | ||||
|     } | ||||
|  | ||||
|     internal static CommandTemplateException MissingLongAndShortName(string template, TemplateToken? token) | ||||
|     { | ||||
|         return CommandLineTemplateExceptionFactory.Create(template, token, | ||||
|             "No long or short name for option has been specified.", | ||||
|             "Missing option. Was this meant to be an argument?"); | ||||
|     } | ||||
|  | ||||
|     internal static CommandTemplateException ArgumentsMustHaveValueName(string template) | ||||
|     { | ||||
|         return CommandLineTemplateExceptionFactory.Create(template, null, | ||||
|             "Arguments must have a value name.", | ||||
|             "Missing value name."); | ||||
|     } | ||||
| } | ||||
| @@ -1,262 +1,261 @@ | ||||
| using System; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| /// <summary> | ||||
| /// Contains extensions for <see cref="IConfigurator"/> | ||||
| /// and <see cref="IConfigurator{TSettings}"/>. | ||||
| /// </summary> | ||||
| public static class ConfiguratorExtensions | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Contains extensions for <see cref="IConfigurator"/> | ||||
|     /// and <see cref="IConfigurator{TSettings}"/>. | ||||
|     /// Sets the name of the application. | ||||
|     /// </summary> | ||||
|     public static class ConfiguratorExtensions | ||||
|     /// <param name="configurator">The configurator.</param> | ||||
|     /// <param name="name">The name of the application.</param> | ||||
|     /// <returns>A configurator that can be used to configure the application further.</returns> | ||||
|     public static IConfigurator SetApplicationName(this IConfigurator configurator, string name) | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Sets the name of the application. | ||||
|         /// </summary> | ||||
|         /// <param name="configurator">The configurator.</param> | ||||
|         /// <param name="name">The name of the application.</param> | ||||
|         /// <returns>A configurator that can be used to configure the application further.</returns> | ||||
|         public static IConfigurator SetApplicationName(this IConfigurator configurator, string name) | ||||
|         if (configurator == null) | ||||
|         { | ||||
|             if (configurator == null) | ||||
|             { | ||||
|                 throw new ArgumentNullException(nameof(configurator)); | ||||
|             } | ||||
|  | ||||
|             configurator.Settings.ApplicationName = name; | ||||
|             return configurator; | ||||
|             throw new ArgumentNullException(nameof(configurator)); | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Overrides the auto-detected version of the application. | ||||
|         /// </summary> | ||||
|         /// <param name="configurator">The configurator.</param> | ||||
|         /// <param name="version">The version of application.</param> | ||||
|         /// <returns>A configurator that can be used to configure the application further.</returns> | ||||
|         public static IConfigurator SetApplicationVersion(this IConfigurator configurator, string version) | ||||
|         { | ||||
|             if (configurator == null) | ||||
|             { | ||||
|                 throw new ArgumentNullException(nameof(configurator)); | ||||
|             } | ||||
|  | ||||
|             configurator.Settings.ApplicationVersion = version; | ||||
|             return configurator; | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Configures the console. | ||||
|         /// </summary> | ||||
|         /// <param name="configurator">The configurator.</param> | ||||
|         /// <param name="console">The console.</param> | ||||
|         /// <returns>A configurator that can be used to configure the application further.</returns> | ||||
|         public static IConfigurator ConfigureConsole(this IConfigurator configurator, IAnsiConsole console) | ||||
|         { | ||||
|             if (configurator == null) | ||||
|             { | ||||
|                 throw new ArgumentNullException(nameof(configurator)); | ||||
|             } | ||||
|  | ||||
|             configurator.Settings.Console = console; | ||||
|             return configurator; | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Sets the parsing mode to strict. | ||||
|         /// </summary> | ||||
|         /// <param name="configurator">The configurator.</param> | ||||
|         /// <returns>A configurator that can be used to configure the application further.</returns> | ||||
|         public static IConfigurator UseStrictParsing(this IConfigurator configurator) | ||||
|         { | ||||
|             if (configurator == null) | ||||
|             { | ||||
|                 throw new ArgumentNullException(nameof(configurator)); | ||||
|             } | ||||
|  | ||||
|             configurator.Settings.StrictParsing = true; | ||||
|             return configurator; | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Tells the command line application to propagate all | ||||
|         /// exceptions to the user. | ||||
|         /// </summary> | ||||
|         /// <param name="configurator">The configurator.</param> | ||||
|         /// <returns>A configurator that can be used to configure the application further.</returns> | ||||
|         public static IConfigurator PropagateExceptions(this IConfigurator configurator) | ||||
|         { | ||||
|             if (configurator == null) | ||||
|             { | ||||
|                 throw new ArgumentNullException(nameof(configurator)); | ||||
|             } | ||||
|  | ||||
|             configurator.Settings.PropagateExceptions = true; | ||||
|             return configurator; | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Configures case sensitivity. | ||||
|         /// </summary> | ||||
|         /// <param name="configurator">The configuration.</param> | ||||
|         /// <param name="sensitivity">The case sensitivity.</param> | ||||
|         /// <returns>A configurator that can be used to configure the application further.</returns> | ||||
|         public static IConfigurator CaseSensitivity(this IConfigurator configurator, CaseSensitivity sensitivity) | ||||
|         { | ||||
|             if (configurator == null) | ||||
|             { | ||||
|                 throw new ArgumentNullException(nameof(configurator)); | ||||
|             } | ||||
|  | ||||
|             configurator.Settings.CaseSensitivity = sensitivity; | ||||
|             return configurator; | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Tells the command line application to validate all | ||||
|         /// examples before running the application. | ||||
|         /// </summary> | ||||
|         /// <param name="configurator">The configurator.</param> | ||||
|         /// <returns>A configurator that can be used to configure the application further.</returns> | ||||
|         public static IConfigurator ValidateExamples(this IConfigurator configurator) | ||||
|         { | ||||
|             if (configurator == null) | ||||
|             { | ||||
|                 throw new ArgumentNullException(nameof(configurator)); | ||||
|             } | ||||
|  | ||||
|             configurator.Settings.ValidateExamples = true; | ||||
|             return configurator; | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Sets the command interceptor to be used. | ||||
|         /// </summary> | ||||
|         /// <param name="configurator">The configurator.</param> | ||||
|         /// <param name="interceptor">A <see cref="ICommandInterceptor"/>.</param> | ||||
|         /// <returns>A configurator that can be used to configure the application further.</returns> | ||||
|         public static IConfigurator SetInterceptor(this IConfigurator configurator, ICommandInterceptor interceptor) | ||||
|         { | ||||
|             if (configurator == null) | ||||
|             { | ||||
|                 throw new ArgumentNullException(nameof(configurator)); | ||||
|             } | ||||
|  | ||||
|             configurator.Settings.Interceptor = interceptor; | ||||
|             return configurator; | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Adds a command branch. | ||||
|         /// </summary> | ||||
|         /// <param name="configurator">The configurator.</param> | ||||
|         /// <param name="name">The name of the command branch.</param> | ||||
|         /// <param name="action">The command branch configuration.</param> | ||||
|         public static void AddBranch( | ||||
|             this IConfigurator configurator, | ||||
|             string name, | ||||
|             Action<IConfigurator<CommandSettings>> action) | ||||
|         { | ||||
|             if (configurator == null) | ||||
|             { | ||||
|                 throw new ArgumentNullException(nameof(configurator)); | ||||
|             } | ||||
|  | ||||
|             configurator.AddBranch(name, action); | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Adds a command branch. | ||||
|         /// </summary> | ||||
|         /// <typeparam name="TSettings">The command setting type.</typeparam> | ||||
|         /// <param name="configurator">The configurator.</param> | ||||
|         /// <param name="name">The name of the command branch.</param> | ||||
|         /// <param name="action">The command branch configuration.</param> | ||||
|         public static void AddBranch<TSettings>( | ||||
|             this IConfigurator<TSettings> configurator, | ||||
|             string name, | ||||
|             Action<IConfigurator<TSettings>> action) | ||||
|                 where TSettings : CommandSettings | ||||
|         { | ||||
|             if (configurator == null) | ||||
|             { | ||||
|                 throw new ArgumentNullException(nameof(configurator)); | ||||
|             } | ||||
|  | ||||
|             configurator.AddBranch(name, action); | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Adds a command without settings that executes a delegate. | ||||
|         /// </summary> | ||||
|         /// <param name="configurator">The configurator.</param> | ||||
|         /// <param name="name">The name of the command.</param> | ||||
|         /// <param name="func">The delegate to execute as part of command execution.</param> | ||||
|         /// <returns>A command configurator that can be used to configure the command further.</returns> | ||||
|         public static ICommandConfigurator AddDelegate( | ||||
|             this IConfigurator configurator, | ||||
|             string name, | ||||
|             Func<CommandContext, int> func) | ||||
|         { | ||||
|             if (configurator == null) | ||||
|             { | ||||
|                 throw new ArgumentNullException(nameof(configurator)); | ||||
|             } | ||||
|  | ||||
|             return configurator.AddDelegate<EmptyCommandSettings>(name, (c, _) => func(c)); | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Adds a command without settings that executes a delegate. | ||||
|         /// </summary> | ||||
|         /// <typeparam name="TSettings">The command setting type.</typeparam> | ||||
|         /// <param name="configurator">The configurator.</param> | ||||
|         /// <param name="name">The name of the command.</param> | ||||
|         /// <param name="func">The delegate to execute as part of command execution.</param> | ||||
|         /// <returns>A command configurator that can be used to configure the command further.</returns> | ||||
|         public static ICommandConfigurator AddDelegate<TSettings>( | ||||
|             this IConfigurator<TSettings> configurator, | ||||
|             string name, | ||||
|             Func<CommandContext, int> func) | ||||
|                 where TSettings : CommandSettings | ||||
|         { | ||||
|             if (configurator == null) | ||||
|             { | ||||
|                 throw new ArgumentNullException(nameof(configurator)); | ||||
|             } | ||||
|  | ||||
|             return configurator.AddDelegate<TSettings>(name, (c, _) => func(c)); | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Sets the ExceptionsHandler. | ||||
|         /// <para>Setting <see cref="ICommandAppSettings.ExceptionHandler"/> this way will use the | ||||
|         /// default exit code of -1.</para> | ||||
|         /// </summary> | ||||
|         /// <param name="configurator">The configurator.</param> | ||||
|         /// <param name="exceptionHandler">The Action that handles the exception.</param> | ||||
|         /// <returns>A configurator that can be used to configure the application further.</returns> | ||||
|         public static IConfigurator SetExceptionHandler(this IConfigurator configurator, Action<Exception> exceptionHandler) | ||||
|         { | ||||
|             return configurator.SetExceptionHandler(ex => | ||||
|             { | ||||
|                 exceptionHandler(ex); | ||||
|                 return -1; | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Sets the ExceptionsHandler. | ||||
|         /// </summary> | ||||
|         /// <param name="configurator">The configurator.</param> | ||||
|         /// <param name="exceptionHandler">The Action that handles the exception.</param> | ||||
|         /// <returns>A configurator that can be used to configure the application further.</returns> | ||||
|         public static IConfigurator SetExceptionHandler(this IConfigurator configurator, Func<Exception, int>? exceptionHandler) | ||||
|         { | ||||
|             if (configurator == null) | ||||
|             { | ||||
|                 throw new ArgumentNullException(nameof(configurator)); | ||||
|             } | ||||
|  | ||||
|             configurator.Settings.ExceptionHandler = exceptionHandler; | ||||
|             return configurator; | ||||
|         } | ||||
|         configurator.Settings.ApplicationName = name; | ||||
|         return configurator; | ||||
|     } | ||||
| } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Overrides the auto-detected version of the application. | ||||
|     /// </summary> | ||||
|     /// <param name="configurator">The configurator.</param> | ||||
|     /// <param name="version">The version of application.</param> | ||||
|     /// <returns>A configurator that can be used to configure the application further.</returns> | ||||
|     public static IConfigurator SetApplicationVersion(this IConfigurator configurator, string version) | ||||
|     { | ||||
|         if (configurator == null) | ||||
|         { | ||||
|             throw new ArgumentNullException(nameof(configurator)); | ||||
|         } | ||||
|  | ||||
|         configurator.Settings.ApplicationVersion = version; | ||||
|         return configurator; | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Configures the console. | ||||
|     /// </summary> | ||||
|     /// <param name="configurator">The configurator.</param> | ||||
|     /// <param name="console">The console.</param> | ||||
|     /// <returns>A configurator that can be used to configure the application further.</returns> | ||||
|     public static IConfigurator ConfigureConsole(this IConfigurator configurator, IAnsiConsole console) | ||||
|     { | ||||
|         if (configurator == null) | ||||
|         { | ||||
|             throw new ArgumentNullException(nameof(configurator)); | ||||
|         } | ||||
|  | ||||
|         configurator.Settings.Console = console; | ||||
|         return configurator; | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Sets the parsing mode to strict. | ||||
|     /// </summary> | ||||
|     /// <param name="configurator">The configurator.</param> | ||||
|     /// <returns>A configurator that can be used to configure the application further.</returns> | ||||
|     public static IConfigurator UseStrictParsing(this IConfigurator configurator) | ||||
|     { | ||||
|         if (configurator == null) | ||||
|         { | ||||
|             throw new ArgumentNullException(nameof(configurator)); | ||||
|         } | ||||
|  | ||||
|         configurator.Settings.StrictParsing = true; | ||||
|         return configurator; | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Tells the command line application to propagate all | ||||
|     /// exceptions to the user. | ||||
|     /// </summary> | ||||
|     /// <param name="configurator">The configurator.</param> | ||||
|     /// <returns>A configurator that can be used to configure the application further.</returns> | ||||
|     public static IConfigurator PropagateExceptions(this IConfigurator configurator) | ||||
|     { | ||||
|         if (configurator == null) | ||||
|         { | ||||
|             throw new ArgumentNullException(nameof(configurator)); | ||||
|         } | ||||
|  | ||||
|         configurator.Settings.PropagateExceptions = true; | ||||
|         return configurator; | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Configures case sensitivity. | ||||
|     /// </summary> | ||||
|     /// <param name="configurator">The configuration.</param> | ||||
|     /// <param name="sensitivity">The case sensitivity.</param> | ||||
|     /// <returns>A configurator that can be used to configure the application further.</returns> | ||||
|     public static IConfigurator CaseSensitivity(this IConfigurator configurator, CaseSensitivity sensitivity) | ||||
|     { | ||||
|         if (configurator == null) | ||||
|         { | ||||
|             throw new ArgumentNullException(nameof(configurator)); | ||||
|         } | ||||
|  | ||||
|         configurator.Settings.CaseSensitivity = sensitivity; | ||||
|         return configurator; | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Tells the command line application to validate all | ||||
|     /// examples before running the application. | ||||
|     /// </summary> | ||||
|     /// <param name="configurator">The configurator.</param> | ||||
|     /// <returns>A configurator that can be used to configure the application further.</returns> | ||||
|     public static IConfigurator ValidateExamples(this IConfigurator configurator) | ||||
|     { | ||||
|         if (configurator == null) | ||||
|         { | ||||
|             throw new ArgumentNullException(nameof(configurator)); | ||||
|         } | ||||
|  | ||||
|         configurator.Settings.ValidateExamples = true; | ||||
|         return configurator; | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Sets the command interceptor to be used. | ||||
|     /// </summary> | ||||
|     /// <param name="configurator">The configurator.</param> | ||||
|     /// <param name="interceptor">A <see cref="ICommandInterceptor"/>.</param> | ||||
|     /// <returns>A configurator that can be used to configure the application further.</returns> | ||||
|     public static IConfigurator SetInterceptor(this IConfigurator configurator, ICommandInterceptor interceptor) | ||||
|     { | ||||
|         if (configurator == null) | ||||
|         { | ||||
|             throw new ArgumentNullException(nameof(configurator)); | ||||
|         } | ||||
|  | ||||
|         configurator.Settings.Interceptor = interceptor; | ||||
|         return configurator; | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Adds a command branch. | ||||
|     /// </summary> | ||||
|     /// <param name="configurator">The configurator.</param> | ||||
|     /// <param name="name">The name of the command branch.</param> | ||||
|     /// <param name="action">The command branch configuration.</param> | ||||
|     public static void AddBranch( | ||||
|         this IConfigurator configurator, | ||||
|         string name, | ||||
|         Action<IConfigurator<CommandSettings>> action) | ||||
|     { | ||||
|         if (configurator == null) | ||||
|         { | ||||
|             throw new ArgumentNullException(nameof(configurator)); | ||||
|         } | ||||
|  | ||||
|         configurator.AddBranch(name, action); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Adds a command branch. | ||||
|     /// </summary> | ||||
|     /// <typeparam name="TSettings">The command setting type.</typeparam> | ||||
|     /// <param name="configurator">The configurator.</param> | ||||
|     /// <param name="name">The name of the command branch.</param> | ||||
|     /// <param name="action">The command branch configuration.</param> | ||||
|     public static void AddBranch<TSettings>( | ||||
|         this IConfigurator<TSettings> configurator, | ||||
|         string name, | ||||
|         Action<IConfigurator<TSettings>> action) | ||||
|             where TSettings : CommandSettings | ||||
|     { | ||||
|         if (configurator == null) | ||||
|         { | ||||
|             throw new ArgumentNullException(nameof(configurator)); | ||||
|         } | ||||
|  | ||||
|         configurator.AddBranch(name, action); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Adds a command without settings that executes a delegate. | ||||
|     /// </summary> | ||||
|     /// <param name="configurator">The configurator.</param> | ||||
|     /// <param name="name">The name of the command.</param> | ||||
|     /// <param name="func">The delegate to execute as part of command execution.</param> | ||||
|     /// <returns>A command configurator that can be used to configure the command further.</returns> | ||||
|     public static ICommandConfigurator AddDelegate( | ||||
|         this IConfigurator configurator, | ||||
|         string name, | ||||
|         Func<CommandContext, int> func) | ||||
|     { | ||||
|         if (configurator == null) | ||||
|         { | ||||
|             throw new ArgumentNullException(nameof(configurator)); | ||||
|         } | ||||
|  | ||||
|         return configurator.AddDelegate<EmptyCommandSettings>(name, (c, _) => func(c)); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Adds a command without settings that executes a delegate. | ||||
|     /// </summary> | ||||
|     /// <typeparam name="TSettings">The command setting type.</typeparam> | ||||
|     /// <param name="configurator">The configurator.</param> | ||||
|     /// <param name="name">The name of the command.</param> | ||||
|     /// <param name="func">The delegate to execute as part of command execution.</param> | ||||
|     /// <returns>A command configurator that can be used to configure the command further.</returns> | ||||
|     public static ICommandConfigurator AddDelegate<TSettings>( | ||||
|         this IConfigurator<TSettings> configurator, | ||||
|         string name, | ||||
|         Func<CommandContext, int> func) | ||||
|             where TSettings : CommandSettings | ||||
|     { | ||||
|         if (configurator == null) | ||||
|         { | ||||
|             throw new ArgumentNullException(nameof(configurator)); | ||||
|         } | ||||
|  | ||||
|         return configurator.AddDelegate<TSettings>(name, (c, _) => func(c)); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Sets the ExceptionsHandler. | ||||
|     /// <para>Setting <see cref="ICommandAppSettings.ExceptionHandler"/> this way will use the | ||||
|     /// default exit code of -1.</para> | ||||
|     /// </summary> | ||||
|     /// <param name="configurator">The configurator.</param> | ||||
|     /// <param name="exceptionHandler">The Action that handles the exception.</param> | ||||
|     /// <returns>A configurator that can be used to configure the application further.</returns> | ||||
|     public static IConfigurator SetExceptionHandler(this IConfigurator configurator, Action<Exception> exceptionHandler) | ||||
|     { | ||||
|         return configurator.SetExceptionHandler(ex => | ||||
|         { | ||||
|             exceptionHandler(ex); | ||||
|             return -1; | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Sets the ExceptionsHandler. | ||||
|     /// </summary> | ||||
|     /// <param name="configurator">The configurator.</param> | ||||
|     /// <param name="exceptionHandler">The Action that handles the exception.</param> | ||||
|     /// <returns>A configurator that can be used to configure the application further.</returns> | ||||
|     public static IConfigurator SetExceptionHandler(this IConfigurator configurator, Func<Exception, int>? exceptionHandler) | ||||
|     { | ||||
|         if (configurator == null) | ||||
|         { | ||||
|             throw new ArgumentNullException(nameof(configurator)); | ||||
|         } | ||||
|  | ||||
|         configurator.Settings.ExceptionHandler = exceptionHandler; | ||||
|         return configurator; | ||||
|     } | ||||
| } | ||||
| @@ -1,9 +1,8 @@ | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| /// <summary> | ||||
| /// Represents empty settings. | ||||
| /// </summary> | ||||
| public sealed class EmptyCommandSettings : CommandSettings | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Represents empty settings. | ||||
|     /// </summary> | ||||
|     public sealed class EmptyCommandSettings : CommandSettings | ||||
|     { | ||||
|     } | ||||
| } | ||||
| } | ||||
| @@ -1,59 +1,58 @@ | ||||
| using System; | ||||
| using System.Globalization; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| /// <summary> | ||||
| /// Implementation of a flag with an optional value. | ||||
| /// </summary> | ||||
| /// <typeparam name="T">The flag's element type.</typeparam> | ||||
| public sealed class FlagValue<T> : IFlagValue | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Implementation of a flag with an optional value. | ||||
|     /// Gets or sets a value indicating whether or not the flag was set or not. | ||||
|     /// </summary> | ||||
|     /// <typeparam name="T">The flag's element type.</typeparam> | ||||
|     public sealed class FlagValue<T> : IFlagValue | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Gets or sets a value indicating whether or not the flag was set or not. | ||||
|         /// </summary> | ||||
|         public bool IsSet { get; set; } | ||||
|     public bool IsSet { get; set; } | ||||
|  | ||||
| #pragma warning disable CS8618 // Non-nullable field is uninitialized. Consider declaring as nullable. | ||||
|         /// <summary> | ||||
|         /// Gets or sets the flag's value. | ||||
|         /// </summary> | ||||
|         public T Value { get; set; } | ||||
|     /// <summary> | ||||
|     /// Gets or sets the flag's value. | ||||
|     /// </summary> | ||||
|     public T Value { get; set; } | ||||
| #pragma warning restore CS8618 // Non-nullable field is uninitialized. Consider declaring as nullable. | ||||
|  | ||||
|         /// <inheritdoc/> | ||||
|         Type IFlagValue.Type => typeof(T); | ||||
|     /// <inheritdoc/> | ||||
|     Type IFlagValue.Type => typeof(T); | ||||
|  | ||||
|         /// <inheritdoc/> | ||||
|         object? IFlagValue.Value | ||||
|     /// <inheritdoc/> | ||||
|     object? IFlagValue.Value | ||||
|     { | ||||
|         get => Value; | ||||
|         set | ||||
|         { | ||||
|             get => Value; | ||||
|             set | ||||
|             { | ||||
| #pragma warning disable CS8601 // Possible null reference assignment. | ||||
| #pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. | ||||
|                 Value = (T)value; | ||||
|             Value = (T)value; | ||||
| #pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type. | ||||
| #pragma warning restore CS8601 // Possible null reference assignment. | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         /// <inheritdoc/> | ||||
|         public override string ToString() | ||||
|         { | ||||
|             var flag = (IFlagValue)this; | ||||
|             if (flag.Value != null) | ||||
|             { | ||||
|                 return string.Format( | ||||
|                     CultureInfo.InvariantCulture, | ||||
|                     "Set={0}, Value={1}", | ||||
|                     IsSet, | ||||
|                     flag.Value.ToString()); | ||||
|             } | ||||
|  | ||||
|             return string.Format( | ||||
|                 CultureInfo.InvariantCulture, | ||||
|                 "Set={0}", IsSet); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
|     /// <inheritdoc/> | ||||
|     public override string ToString() | ||||
|     { | ||||
|         var flag = (IFlagValue)this; | ||||
|         if (flag.Value != null) | ||||
|         { | ||||
|             return string.Format( | ||||
|                 CultureInfo.InvariantCulture, | ||||
|                 "Set={0}, Value={1}", | ||||
|                 IsSet, | ||||
|                 flag.Value.ToString()); | ||||
|         } | ||||
|  | ||||
|         return string.Format( | ||||
|             CultureInfo.InvariantCulture, | ||||
|             "Set={0}", IsSet); | ||||
|     } | ||||
| } | ||||
| @@ -1,26 +1,25 @@ | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| /// <summary> | ||||
| /// Represents a command. | ||||
| /// </summary> | ||||
| public interface ICommand | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Represents a command. | ||||
|     /// Validates the specified settings and remaining arguments. | ||||
|     /// </summary> | ||||
|     public interface ICommand | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Validates the specified settings and remaining arguments. | ||||
|         /// </summary> | ||||
|         /// <param name="context">The command context.</param> | ||||
|         /// <param name="settings">The settings.</param> | ||||
|         /// <returns>The validation result.</returns> | ||||
|         ValidationResult Validate(CommandContext context, CommandSettings settings); | ||||
|     /// <param name="context">The command context.</param> | ||||
|     /// <param name="settings">The settings.</param> | ||||
|     /// <returns>The validation result.</returns> | ||||
|     ValidationResult Validate(CommandContext context, CommandSettings settings); | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Executes the command. | ||||
|         /// </summary> | ||||
|         /// <param name="context">The command context.</param> | ||||
|         /// <param name="settings">The settings.</param> | ||||
|         /// <returns>The validation result.</returns> | ||||
|         Task<int> Execute(CommandContext context, CommandSettings settings); | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// Executes the command. | ||||
|     /// </summary> | ||||
|     /// <param name="context">The command context.</param> | ||||
|     /// <param name="settings">The settings.</param> | ||||
|     /// <returns>The validation result.</returns> | ||||
|     Task<int> Execute(CommandContext context, CommandSettings settings); | ||||
| } | ||||
| @@ -2,31 +2,30 @@ using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| /// <summary> | ||||
| /// Represents a command line application. | ||||
| /// </summary> | ||||
| public interface ICommandApp | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Represents a command line application. | ||||
|     /// Configures the command line application. | ||||
|     /// </summary> | ||||
|     public interface ICommandApp | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Configures the command line application. | ||||
|         /// </summary> | ||||
|         /// <param name="configuration">The configuration.</param> | ||||
|         void Configure(Action<IConfigurator> configuration); | ||||
|     /// <param name="configuration">The configuration.</param> | ||||
|     void Configure(Action<IConfigurator> configuration); | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Runs the command line application with specified arguments. | ||||
|         /// </summary> | ||||
|         /// <param name="args">The arguments.</param> | ||||
|         /// <returns>The exit code from the executed command.</returns> | ||||
|         int Run(IEnumerable<string> args); | ||||
|     /// <summary> | ||||
|     /// Runs the command line application with specified arguments. | ||||
|     /// </summary> | ||||
|     /// <param name="args">The arguments.</param> | ||||
|     /// <returns>The exit code from the executed command.</returns> | ||||
|     int Run(IEnumerable<string> args); | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Runs the command line application with specified arguments. | ||||
|         /// </summary> | ||||
|         /// <param name="args">The arguments.</param> | ||||
|         /// <returns>The exit code from the executed command.</returns> | ||||
|         Task<int> RunAsync(IEnumerable<string> args); | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// Runs the command line application with specified arguments. | ||||
|     /// </summary> | ||||
|     /// <param name="args">The arguments.</param> | ||||
|     /// <returns>The exit code from the executed command.</returns> | ||||
|     Task<int> RunAsync(IEnumerable<string> args); | ||||
| } | ||||
| @@ -1,64 +1,63 @@ | ||||
| using System; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| /// <summary> | ||||
| /// Represents a command line application settings. | ||||
| /// </summary> | ||||
| public interface ICommandAppSettings | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Represents a command line application settings. | ||||
|     /// Gets or sets the application name. | ||||
|     /// </summary> | ||||
|     public interface ICommandAppSettings | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Gets or sets the application name. | ||||
|         /// </summary> | ||||
|         string? ApplicationName { get; set; } | ||||
|     string? ApplicationName { get; set; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets or sets the application version (use it to override auto-detected value). | ||||
|         /// </summary> | ||||
|         string? ApplicationVersion { get; set; } | ||||
|     /// <summary> | ||||
|     /// Gets or sets the application version (use it to override auto-detected value). | ||||
|     /// </summary> | ||||
|     string? ApplicationVersion { get; set; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets or sets the <see cref="IAnsiConsole"/>. | ||||
|         /// </summary> | ||||
|         IAnsiConsole? Console { get; set; } | ||||
|     /// <summary> | ||||
|     /// Gets or sets the <see cref="IAnsiConsole"/>. | ||||
|     /// </summary> | ||||
|     IAnsiConsole? Console { get; set; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets or sets the <see cref="ICommandInterceptor"/> used | ||||
|         /// to intercept settings before it's being sent to the command. | ||||
|         /// </summary> | ||||
|         ICommandInterceptor? Interceptor { get; set; } | ||||
|     /// <summary> | ||||
|     /// Gets or sets the <see cref="ICommandInterceptor"/> used | ||||
|     /// to intercept settings before it's being sent to the command. | ||||
|     /// </summary> | ||||
|     ICommandInterceptor? Interceptor { get; set; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets the type registrar. | ||||
|         /// </summary> | ||||
|         ITypeRegistrarFrontend Registrar { get; } | ||||
|     /// <summary> | ||||
|     /// Gets the type registrar. | ||||
|     /// </summary> | ||||
|     ITypeRegistrarFrontend Registrar { get; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets or sets case sensitivity. | ||||
|         /// </summary> | ||||
|         CaseSensitivity CaseSensitivity { get; set; } | ||||
|     /// <summary> | ||||
|     /// Gets or sets case sensitivity. | ||||
|     /// </summary> | ||||
|     CaseSensitivity CaseSensitivity { get; set; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets or sets a value indicating whether or not parsing is strict. | ||||
|         /// </summary> | ||||
|         bool StrictParsing { get; set; } | ||||
|     /// <summary> | ||||
|     /// Gets or sets a value indicating whether or not parsing is strict. | ||||
|     /// </summary> | ||||
|     bool StrictParsing { get; set; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets or sets a value indicating whether or not exceptions should be propagated. | ||||
|         /// <para>Setting this to <c>true</c> will disable default Exception handling and | ||||
|         /// any <see cref="ExceptionHandler"/>, if set.</para> | ||||
|         /// </summary> | ||||
|         bool PropagateExceptions { get; set; } | ||||
|     /// <summary> | ||||
|     /// Gets or sets a value indicating whether or not exceptions should be propagated. | ||||
|     /// <para>Setting this to <c>true</c> will disable default Exception handling and | ||||
|     /// any <see cref="ExceptionHandler"/>, if set.</para> | ||||
|     /// </summary> | ||||
|     bool PropagateExceptions { get; set; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets or sets a value indicating whether or not examples should be validated. | ||||
|         /// </summary> | ||||
|         bool ValidateExamples { get; set; } | ||||
|     /// <summary> | ||||
|     /// Gets or sets a value indicating whether or not examples should be validated. | ||||
|     /// </summary> | ||||
|     bool ValidateExamples { get; set; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets or sets a handler for Exceptions. | ||||
|         /// <para>This handler will not be called, if <see cref="PropagateExceptions"/> is set to <c>true</c>.</para> | ||||
|         /// </summary> | ||||
|         public Func<Exception, int>? ExceptionHandler { get; set; } | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// Gets or sets a handler for Exceptions. | ||||
|     /// <para>This handler will not be called, if <see cref="PropagateExceptions"/> is set to <c>true</c>.</para> | ||||
|     /// </summary> | ||||
|     public Func<Exception, int>? ExceptionHandler { get; set; } | ||||
| } | ||||
| @@ -1,44 +1,43 @@ | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| /// <summary> | ||||
| /// Represents a command configurator. | ||||
| /// </summary> | ||||
| public interface ICommandConfigurator | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Represents a command configurator. | ||||
|     /// Adds an example of how to use the command. | ||||
|     /// </summary> | ||||
|     public interface ICommandConfigurator | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Adds an example of how to use the command. | ||||
|         /// </summary> | ||||
|         /// <param name="args">The example arguments.</param> | ||||
|         /// <returns>The same <see cref="ICommandConfigurator"/> instance so that multiple calls can be chained.</returns> | ||||
|         ICommandConfigurator WithExample(string[] args); | ||||
|     /// <param name="args">The example arguments.</param> | ||||
|     /// <returns>The same <see cref="ICommandConfigurator"/> instance so that multiple calls can be chained.</returns> | ||||
|     ICommandConfigurator WithExample(string[] args); | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Adds an alias (an alternative name) to the command being configured. | ||||
|         /// </summary> | ||||
|         /// <param name="name">The alias to add to the command being configured.</param> | ||||
|         /// <returns>The same <see cref="ICommandConfigurator"/> instance so that multiple calls can be chained.</returns> | ||||
|         ICommandConfigurator WithAlias(string name); | ||||
|     /// <summary> | ||||
|     /// Adds an alias (an alternative name) to the command being configured. | ||||
|     /// </summary> | ||||
|     /// <param name="name">The alias to add to the command being configured.</param> | ||||
|     /// <returns>The same <see cref="ICommandConfigurator"/> instance so that multiple calls can be chained.</returns> | ||||
|     ICommandConfigurator WithAlias(string name); | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Sets the description of the command. | ||||
|         /// </summary> | ||||
|         /// <param name="description">The command description.</param> | ||||
|         /// <returns>The same <see cref="ICommandConfigurator"/> instance so that multiple calls can be chained.</returns> | ||||
|         ICommandConfigurator WithDescription(string description); | ||||
|     /// <summary> | ||||
|     /// Sets the description of the command. | ||||
|     /// </summary> | ||||
|     /// <param name="description">The command description.</param> | ||||
|     /// <returns>The same <see cref="ICommandConfigurator"/> instance so that multiple calls can be chained.</returns> | ||||
|     ICommandConfigurator WithDescription(string description); | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Sets data that will be passed to the command via the <see cref="CommandContext"/>. | ||||
|         /// </summary> | ||||
|         /// <param name="data">The data to pass to the command.</param> | ||||
|         /// <returns>The same <see cref="ICommandConfigurator"/> instance so that multiple calls can be chained.</returns> | ||||
|         ICommandConfigurator WithData(object data); | ||||
|     /// <summary> | ||||
|     /// Sets data that will be passed to the command via the <see cref="CommandContext"/>. | ||||
|     /// </summary> | ||||
|     /// <param name="data">The data to pass to the command.</param> | ||||
|     /// <returns>The same <see cref="ICommandConfigurator"/> instance so that multiple calls can be chained.</returns> | ||||
|     ICommandConfigurator WithData(object data); | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Marks the command as hidden. | ||||
|         /// Hidden commands do not show up in help documentation or | ||||
|         /// generated XML models. | ||||
|         /// </summary> | ||||
|         /// <returns>The same <see cref="ICommandConfigurator"/> instance so that multiple calls can be chained.</returns> | ||||
|         ICommandConfigurator IsHidden(); | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// Marks the command as hidden. | ||||
|     /// Hidden commands do not show up in help documentation or | ||||
|     /// generated XML models. | ||||
|     /// </summary> | ||||
|     /// <returns>The same <see cref="ICommandConfigurator"/> instance so that multiple calls can be chained.</returns> | ||||
|     ICommandConfigurator IsHidden(); | ||||
| } | ||||
| @@ -1,17 +1,16 @@ | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| /// <summary> | ||||
| /// Represents a command settings interceptor that | ||||
| /// will intercept command settings before it's | ||||
| /// passed to a command. | ||||
| /// </summary> | ||||
| public interface ICommandInterceptor | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Represents a command settings interceptor that | ||||
|     /// will intercept command settings before it's | ||||
|     /// passed to a command. | ||||
|     /// Intercepts command information before it's passed to a command. | ||||
|     /// </summary> | ||||
|     public interface ICommandInterceptor | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Intercepts command information before it's passed to a command. | ||||
|         /// </summary> | ||||
|         /// <param name="context">The intercepted <see cref="CommandContext"/>.</param> | ||||
|         /// <param name="settings">The intercepted <see cref="CommandSettings"/>.</param> | ||||
|         void Intercept(CommandContext context, CommandSettings settings); | ||||
|     } | ||||
| } | ||||
|     /// <param name="context">The intercepted <see cref="CommandContext"/>.</param> | ||||
|     /// <param name="settings">The intercepted <see cref="CommandSettings"/>.</param> | ||||
|     void Intercept(CommandContext context, CommandSettings settings); | ||||
| } | ||||
| @@ -1,12 +1,11 @@ | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| /// <summary> | ||||
| /// Represents a command limiter. | ||||
| /// </summary> | ||||
| /// <typeparam name="TSettings">The type of the settings to limit to.</typeparam> | ||||
| /// <seealso cref="ICommand" /> | ||||
| public interface ICommandLimiter<out TSettings> : ICommand | ||||
|     where TSettings : CommandSettings | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Represents a command limiter. | ||||
|     /// </summary> | ||||
|     /// <typeparam name="TSettings">The type of the settings to limit to.</typeparam> | ||||
|     /// <seealso cref="ICommand" /> | ||||
|     public interface ICommandLimiter<out TSettings> : ICommand | ||||
|         where TSettings : CommandSettings | ||||
|     { | ||||
|     } | ||||
| } | ||||
| } | ||||
| @@ -1,20 +1,19 @@ | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| /// <summary> | ||||
| /// Represents a command. | ||||
| /// </summary> | ||||
| /// <typeparam name="TSettings">The settings type.</typeparam> | ||||
| public interface ICommand<TSettings> : ICommandLimiter<TSettings> | ||||
|     where TSettings : CommandSettings | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Represents a command. | ||||
|     /// Executes the command. | ||||
|     /// </summary> | ||||
|     /// <typeparam name="TSettings">The settings type.</typeparam> | ||||
|     public interface ICommand<TSettings> : ICommandLimiter<TSettings> | ||||
|         where TSettings : CommandSettings | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Executes the command. | ||||
|         /// </summary> | ||||
|         /// <param name="context">The command context.</param> | ||||
|         /// <param name="settings">The settings.</param> | ||||
|         /// <returns>An integer indicating whether or not the command executed successfully.</returns> | ||||
|         Task<int> Execute(CommandContext context, TSettings settings); | ||||
|     } | ||||
| } | ||||
|     /// <param name="context">The command context.</param> | ||||
|     /// <param name="settings">The settings.</param> | ||||
|     /// <returns>An integer indicating whether or not the command executed successfully.</returns> | ||||
|     Task<int> Execute(CommandContext context, TSettings settings); | ||||
| } | ||||
| @@ -1,27 +1,26 @@ | ||||
| using System; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| /// <summary> | ||||
| /// Represents a command parameter. | ||||
| /// </summary> | ||||
| public interface ICommandParameterInfo | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Represents a command parameter. | ||||
|     /// Gets the property name. | ||||
|     /// </summary> | ||||
|     public interface ICommandParameterInfo | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Gets the property name. | ||||
|         /// </summary> | ||||
|         /// <value>The property name.</value> | ||||
|         public string PropertyName { get; } | ||||
|     /// <value>The property name.</value> | ||||
|     public string PropertyName { get; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets the parameter type. | ||||
|         /// </summary> | ||||
|         public Type ParameterType { get; } | ||||
|     /// <summary> | ||||
|     /// Gets the parameter type. | ||||
|     /// </summary> | ||||
|     public Type ParameterType { get; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets the description. | ||||
|         /// </summary> | ||||
|         /// <value>The description.</value> | ||||
|         public string? Description { get; } | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// Gets the description. | ||||
|     /// </summary> | ||||
|     /// <value>The description.</value> | ||||
|     public string? Description { get; } | ||||
| } | ||||
| @@ -1,49 +1,48 @@ | ||||
| using System; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| /// <summary> | ||||
| /// Represents a configurator. | ||||
| /// </summary> | ||||
| public interface IConfigurator | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Represents a configurator. | ||||
|     /// Gets the command app settings. | ||||
|     /// </summary> | ||||
|     public interface IConfigurator | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Gets the command app settings. | ||||
|         /// </summary> | ||||
|         public ICommandAppSettings Settings { get; } | ||||
|     public ICommandAppSettings Settings { get; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Adds an example of how to use the application. | ||||
|         /// </summary> | ||||
|         /// <param name="args">The example arguments.</param> | ||||
|         void AddExample(string[] args); | ||||
|     /// <summary> | ||||
|     /// Adds an example of how to use the application. | ||||
|     /// </summary> | ||||
|     /// <param name="args">The example arguments.</param> | ||||
|     void AddExample(string[] args); | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Adds a command. | ||||
|         /// </summary> | ||||
|         /// <typeparam name="TCommand">The command type.</typeparam> | ||||
|         /// <param name="name">The name of the command.</param> | ||||
|         /// <returns>A command configurator that can be used to configure the command further.</returns> | ||||
|         ICommandConfigurator AddCommand<TCommand>(string name) | ||||
|             where TCommand : class, ICommand; | ||||
|     /// <summary> | ||||
|     /// Adds a command. | ||||
|     /// </summary> | ||||
|     /// <typeparam name="TCommand">The command type.</typeparam> | ||||
|     /// <param name="name">The name of the command.</param> | ||||
|     /// <returns>A command configurator that can be used to configure the command further.</returns> | ||||
|     ICommandConfigurator AddCommand<TCommand>(string name) | ||||
|         where TCommand : class, ICommand; | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Adds a command that executes a delegate. | ||||
|         /// </summary> | ||||
|         /// <typeparam name="TSettings">The command setting type.</typeparam> | ||||
|         /// <param name="name">The name of the command.</param> | ||||
|         /// <param name="func">The delegate to execute as part of command execution.</param> | ||||
|         /// <returns>A command configurator that can be used to configure the command further.</returns> | ||||
|         ICommandConfigurator AddDelegate<TSettings>(string name, Func<CommandContext, TSettings, int> func) | ||||
|             where TSettings : CommandSettings; | ||||
|     /// <summary> | ||||
|     /// Adds a command that executes a delegate. | ||||
|     /// </summary> | ||||
|     /// <typeparam name="TSettings">The command setting type.</typeparam> | ||||
|     /// <param name="name">The name of the command.</param> | ||||
|     /// <param name="func">The delegate to execute as part of command execution.</param> | ||||
|     /// <returns>A command configurator that can be used to configure the command further.</returns> | ||||
|     ICommandConfigurator AddDelegate<TSettings>(string name, Func<CommandContext, TSettings, int> func) | ||||
|         where TSettings : CommandSettings; | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Adds a command branch. | ||||
|         /// </summary> | ||||
|         /// <typeparam name="TSettings">The command setting type.</typeparam> | ||||
|         /// <param name="name">The name of the command branch.</param> | ||||
|         /// <param name="action">The command branch configurator.</param> | ||||
|         void AddBranch<TSettings>(string name, Action<IConfigurator<TSettings>> action) | ||||
|             where TSettings : CommandSettings; | ||||
|     } | ||||
|     /// <summary> | ||||
|     /// Adds a command branch. | ||||
|     /// </summary> | ||||
|     /// <typeparam name="TSettings">The command setting type.</typeparam> | ||||
|     /// <param name="name">The name of the command branch.</param> | ||||
|     /// <param name="action">The command branch configurator.</param> | ||||
|     void AddBranch<TSettings>(string name, Action<IConfigurator<TSettings>> action) | ||||
|         where TSettings : CommandSettings; | ||||
| } | ||||
| @@ -1,59 +1,58 @@ | ||||
| using System; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| /// <summary> | ||||
| /// Represents a configurator for specific settings. | ||||
| /// </summary> | ||||
| /// <typeparam name="TSettings">The command setting type.</typeparam> | ||||
| public interface IConfigurator<in TSettings> | ||||
|     where TSettings : CommandSettings | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Represents a configurator for specific settings. | ||||
|     /// Sets the description of the branch. | ||||
|     /// </summary> | ||||
|     /// <typeparam name="TSettings">The command setting type.</typeparam> | ||||
|     public interface IConfigurator<in TSettings> | ||||
|         where TSettings : CommandSettings | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Sets the description of the branch. | ||||
|         /// </summary> | ||||
|         /// <param name="description">The description of the branch.</param> | ||||
|         void SetDescription(string description); | ||||
|     /// <param name="description">The description of the branch.</param> | ||||
|     void SetDescription(string description); | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Adds an example of how to use the branch. | ||||
|         /// </summary> | ||||
|         /// <param name="args">The example arguments.</param> | ||||
|         void AddExample(string[] args); | ||||
|     /// <summary> | ||||
|     /// Adds an example of how to use the branch. | ||||
|     /// </summary> | ||||
|     /// <param name="args">The example arguments.</param> | ||||
|     void AddExample(string[] args); | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Marks the branch as hidden. | ||||
|         /// Hidden branches do not show up in help documentation or | ||||
|         /// generated XML models. | ||||
|         /// </summary> | ||||
|         void HideBranch(); | ||||
|     /// <summary> | ||||
|     /// Marks the branch as hidden. | ||||
|     /// Hidden branches do not show up in help documentation or | ||||
|     /// generated XML models. | ||||
|     /// </summary> | ||||
|     void HideBranch(); | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Adds a command. | ||||
|         /// </summary> | ||||
|         /// <typeparam name="TCommand">The command type.</typeparam> | ||||
|         /// <param name="name">The name of the command.</param> | ||||
|         /// <returns>A command configurator that can be used to configure the command further.</returns> | ||||
|         ICommandConfigurator AddCommand<TCommand>(string name) | ||||
|             where TCommand : class, ICommandLimiter<TSettings>; | ||||
|     /// <summary> | ||||
|     /// Adds a command. | ||||
|     /// </summary> | ||||
|     /// <typeparam name="TCommand">The command type.</typeparam> | ||||
|     /// <param name="name">The name of the command.</param> | ||||
|     /// <returns>A command configurator that can be used to configure the command further.</returns> | ||||
|     ICommandConfigurator AddCommand<TCommand>(string name) | ||||
|         where TCommand : class, ICommandLimiter<TSettings>; | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Adds a command that executes a delegate. | ||||
|         /// </summary> | ||||
|         /// <typeparam name="TDerivedSettings">The derived command setting type.</typeparam> | ||||
|         /// <param name="name">The name of the command.</param> | ||||
|         /// <param name="func">The delegate to execute as part of command execution.</param> | ||||
|         /// <returns>A command configurator that can be used to configure the command further.</returns> | ||||
|         ICommandConfigurator AddDelegate<TDerivedSettings>(string name, Func<CommandContext, TDerivedSettings, int> func) | ||||
|             where TDerivedSettings : TSettings; | ||||
|     /// <summary> | ||||
|     /// Adds a command that executes a delegate. | ||||
|     /// </summary> | ||||
|     /// <typeparam name="TDerivedSettings">The derived command setting type.</typeparam> | ||||
|     /// <param name="name">The name of the command.</param> | ||||
|     /// <param name="func">The delegate to execute as part of command execution.</param> | ||||
|     /// <returns>A command configurator that can be used to configure the command further.</returns> | ||||
|     ICommandConfigurator AddDelegate<TDerivedSettings>(string name, Func<CommandContext, TDerivedSettings, int> func) | ||||
|         where TDerivedSettings : TSettings; | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Adds a command branch. | ||||
|         /// </summary> | ||||
|         /// <typeparam name="TDerivedSettings">The derived command setting type.</typeparam> | ||||
|         /// <param name="name">The name of the command branch.</param> | ||||
|         /// <param name="action">The command branch configuration.</param> | ||||
|         void AddBranch<TDerivedSettings>(string name, Action<IConfigurator<TDerivedSettings>> action) | ||||
|             where TDerivedSettings : TSettings; | ||||
|     } | ||||
| } | ||||
|     /// <summary> | ||||
|     /// Adds a command branch. | ||||
|     /// </summary> | ||||
|     /// <typeparam name="TDerivedSettings">The derived command setting type.</typeparam> | ||||
|     /// <param name="name">The name of the command branch.</param> | ||||
|     /// <param name="action">The command branch configuration.</param> | ||||
|     void AddBranch<TDerivedSettings>(string name, Action<IConfigurator<TDerivedSettings>> action) | ||||
|         where TDerivedSettings : TSettings; | ||||
| } | ||||
| @@ -1,25 +1,24 @@ | ||||
| using System; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| /// <summary> | ||||
| /// Represents a flag with an optional value. | ||||
| /// </summary> | ||||
| public interface IFlagValue | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Represents a flag with an optional value. | ||||
|     /// Gets or sets a value indicating whether or not the flag was set or not. | ||||
|     /// </summary> | ||||
|     public interface IFlagValue | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Gets or sets a value indicating whether or not the flag was set or not. | ||||
|         /// </summary> | ||||
|         bool IsSet { get; set; } | ||||
|     bool IsSet { get; set; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets the flag's element type. | ||||
|         /// </summary> | ||||
|         Type Type { get; } | ||||
|     /// <summary> | ||||
|     /// Gets the flag's element type. | ||||
|     /// </summary> | ||||
|     Type Type { get; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets or sets the flag's value. | ||||
|         /// </summary> | ||||
|         object? Value { get; set; } | ||||
|     } | ||||
| } | ||||
|     /// <summary> | ||||
|     /// Gets or sets the flag's value. | ||||
|     /// </summary> | ||||
|     object? Value { get; set; } | ||||
| } | ||||
| @@ -1,21 +1,20 @@ | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| /// <summary> | ||||
| /// Represents the remaining arguments. | ||||
| /// </summary> | ||||
| public interface IRemainingArguments | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Represents the remaining arguments. | ||||
|     /// Gets the parsed remaining arguments. | ||||
|     /// </summary> | ||||
|     public interface IRemainingArguments | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Gets the parsed remaining arguments. | ||||
|         /// </summary> | ||||
|         ILookup<string, string?> Parsed { get; } | ||||
|     ILookup<string, string?> Parsed { get; } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Gets the raw, non-parsed remaining arguments. | ||||
|         /// </summary> | ||||
|         IReadOnlyList<string> Raw { get; } | ||||
|     } | ||||
| } | ||||
|     /// <summary> | ||||
|     /// Gets the raw, non-parsed remaining arguments. | ||||
|     /// </summary> | ||||
|     IReadOnlyList<string> Raw { get; } | ||||
| } | ||||
| @@ -1,38 +1,37 @@ | ||||
| using System; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| /// <summary> | ||||
| /// Represents a type registrar. | ||||
| /// </summary> | ||||
| public interface ITypeRegistrar | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Represents a type registrar. | ||||
|     /// Registers the specified service. | ||||
|     /// </summary> | ||||
|     public interface ITypeRegistrar | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Registers the specified service. | ||||
|         /// </summary> | ||||
|         /// <param name="service">The service.</param> | ||||
|         /// <param name="implementation">The implementation.</param> | ||||
|         void Register(Type service, Type implementation); | ||||
|     /// <param name="service">The service.</param> | ||||
|     /// <param name="implementation">The implementation.</param> | ||||
|     void Register(Type service, Type implementation); | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Registers the specified instance. | ||||
|         /// </summary> | ||||
|         /// <param name="service">The service.</param> | ||||
|         /// <param name="implementation">The implementation.</param> | ||||
|         void RegisterInstance(Type service, object implementation); | ||||
|     /// <summary> | ||||
|     /// Registers the specified instance. | ||||
|     /// </summary> | ||||
|     /// <param name="service">The service.</param> | ||||
|     /// <param name="implementation">The implementation.</param> | ||||
|     void RegisterInstance(Type service, object implementation); | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Registers the specified instance lazily. | ||||
|         /// </summary> | ||||
|         /// <param name="service">The service.</param> | ||||
|         /// <param name="factory">The factory that creates the implementation.</param> | ||||
|         void RegisterLazy(Type service, Func<object> factory); | ||||
|     /// <summary> | ||||
|     /// Registers the specified instance lazily. | ||||
|     /// </summary> | ||||
|     /// <param name="service">The service.</param> | ||||
|     /// <param name="factory">The factory that creates the implementation.</param> | ||||
|     void RegisterLazy(Type service, Func<object> factory); | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Builds the type resolver representing the registrations | ||||
|         /// specified in the current instance. | ||||
|         /// </summary> | ||||
|         /// <returns>A type resolver.</returns> | ||||
|         ITypeResolver Build(); | ||||
|     } | ||||
| } | ||||
|     /// <summary> | ||||
|     /// Builds the type resolver representing the registrations | ||||
|     /// specified in the current instance. | ||||
|     /// </summary> | ||||
|     /// <returns>A type resolver.</returns> | ||||
|     ITypeResolver Build(); | ||||
| } | ||||
| @@ -1,32 +1,31 @@ | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| /// <summary> | ||||
| /// Represents a user friendly frontend for a <see cref="ITypeRegistrar"/>. | ||||
| /// </summary> | ||||
| public interface ITypeRegistrarFrontend | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Represents a user friendly frontend for a <see cref="ITypeRegistrar"/>. | ||||
|     /// Registers the type with the type registrar as a singleton. | ||||
|     /// </summary> | ||||
|     public interface ITypeRegistrarFrontend | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Registers the type with the type registrar as a singleton. | ||||
|         /// </summary> | ||||
|         /// <typeparam name="TService">The exposed service type.</typeparam> | ||||
|         /// <typeparam name="TImplementation">The implementing type.</typeparam> | ||||
|         void Register<TService, TImplementation>() | ||||
|             where TImplementation : TService; | ||||
|     /// <typeparam name="TService">The exposed service type.</typeparam> | ||||
|     /// <typeparam name="TImplementation">The implementing type.</typeparam> | ||||
|     void Register<TService, TImplementation>() | ||||
|         where TImplementation : TService; | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Registers the specified instance with the type registrar as a singleton. | ||||
|         /// </summary> | ||||
|         /// <typeparam name="TImplementation">The type of the instance.</typeparam> | ||||
|         /// <param name="instance">The instance to register.</param> | ||||
|         void RegisterInstance<TImplementation>(TImplementation instance); | ||||
|     /// <summary> | ||||
|     /// Registers the specified instance with the type registrar as a singleton. | ||||
|     /// </summary> | ||||
|     /// <typeparam name="TImplementation">The type of the instance.</typeparam> | ||||
|     /// <param name="instance">The instance to register.</param> | ||||
|     void RegisterInstance<TImplementation>(TImplementation instance); | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Registers the specified instance with the type registrar as a singleton. | ||||
|         /// </summary> | ||||
|         /// <typeparam name="TService">The exposed service type.</typeparam> | ||||
|         /// <typeparam name="TImplementation"> implementing type.</typeparam> | ||||
|         /// <param name="instance">The instance to register.</param> | ||||
|         void RegisterInstance<TService, TImplementation>(TImplementation instance) | ||||
|             where TImplementation : TService; | ||||
|     } | ||||
| } | ||||
|     /// <summary> | ||||
|     /// Registers the specified instance with the type registrar as a singleton. | ||||
|     /// </summary> | ||||
|     /// <typeparam name="TService">The exposed service type.</typeparam> | ||||
|     /// <typeparam name="TImplementation"> implementing type.</typeparam> | ||||
|     /// <param name="instance">The instance to register.</param> | ||||
|     void RegisterInstance<TService, TImplementation>(TImplementation instance) | ||||
|         where TImplementation : TService; | ||||
| } | ||||
| @@ -1,17 +1,16 @@ | ||||
| using System; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| /// <summary> | ||||
| /// Represents a type resolver. | ||||
| /// </summary> | ||||
| public interface ITypeResolver | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Represents a type resolver. | ||||
|     /// Resolves an instance of the specified type. | ||||
|     /// </summary> | ||||
|     public interface ITypeResolver | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Resolves an instance of the specified type. | ||||
|         /// </summary> | ||||
|         /// <param name="type">The type to resolve.</param> | ||||
|         /// <returns>An instance of the specified type, or <c>null</c> if no registration for the specified type exists.</returns> | ||||
|         object? Resolve(Type? type); | ||||
|     } | ||||
| } | ||||
|     /// <param name="type">The type to resolve.</param> | ||||
|     /// <returns>An instance of the specified type, or <c>null</c> if no registration for the specified type exists.</returns> | ||||
|     object? Resolve(Type? type); | ||||
| } | ||||
| @@ -2,54 +2,53 @@ using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Reflection; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| internal static class CommandConstructorBinder | ||||
| { | ||||
|     internal static class CommandConstructorBinder | ||||
|     public static CommandSettings CreateSettings(CommandValueLookup lookup, ConstructorInfo constructor, ITypeResolver resolver) | ||||
|     { | ||||
|         public static CommandSettings CreateSettings(CommandValueLookup lookup, ConstructorInfo constructor, ITypeResolver resolver) | ||||
|         if (constructor.DeclaringType == null) | ||||
|         { | ||||
|             if (constructor.DeclaringType == null) | ||||
|             { | ||||
|                 throw new InvalidOperationException("Cannot create settings since constructor have no declaring type."); | ||||
|             } | ||||
|  | ||||
|             var parameters = new List<object?>(); | ||||
|             var mapped = new HashSet<Guid>(); | ||||
|             foreach (var parameter in constructor.GetParameters()) | ||||
|             { | ||||
|                 if (lookup.TryGetParameterWithName(parameter.Name, out var result)) | ||||
|                 { | ||||
|                     parameters.Add(result.Value); | ||||
|                     mapped.Add(result.Parameter.Id); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     var value = resolver.Resolve(parameter.ParameterType); | ||||
|                     if (value == null) | ||||
|                     { | ||||
|                         throw CommandRuntimeException.CouldNotResolveType(parameter.ParameterType); | ||||
|                     } | ||||
|  | ||||
|                     parameters.Add(value); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             // Create the settings. | ||||
|             if (!(Activator.CreateInstance(constructor.DeclaringType, parameters.ToArray()) is CommandSettings settings)) | ||||
|             { | ||||
|                 throw new InvalidOperationException("Could not create settings"); | ||||
|             } | ||||
|  | ||||
|             // Try to do property injection for parameters that wasn't injected. | ||||
|             foreach (var (parameter, value) in lookup) | ||||
|             { | ||||
|                 if (!mapped.Contains(parameter.Id) && parameter.Property.SetMethod != null) | ||||
|                 { | ||||
|                     parameter.Property.SetValue(settings, value); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             return settings; | ||||
|             throw new InvalidOperationException("Cannot create settings since constructor have no declaring type."); | ||||
|         } | ||||
|  | ||||
|         var parameters = new List<object?>(); | ||||
|         var mapped = new HashSet<Guid>(); | ||||
|         foreach (var parameter in constructor.GetParameters()) | ||||
|         { | ||||
|             if (lookup.TryGetParameterWithName(parameter.Name, out var result)) | ||||
|             { | ||||
|                 parameters.Add(result.Value); | ||||
|                 mapped.Add(result.Parameter.Id); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 var value = resolver.Resolve(parameter.ParameterType); | ||||
|                 if (value == null) | ||||
|                 { | ||||
|                     throw CommandRuntimeException.CouldNotResolveType(parameter.ParameterType); | ||||
|                 } | ||||
|  | ||||
|                 parameters.Add(value); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Create the settings. | ||||
|         if (!(Activator.CreateInstance(constructor.DeclaringType, parameters.ToArray()) is CommandSettings settings)) | ||||
|         { | ||||
|             throw new InvalidOperationException("Could not create settings"); | ||||
|         } | ||||
|  | ||||
|         // Try to do property injection for parameters that wasn't injected. | ||||
|         foreach (var (parameter, value) in lookup) | ||||
|         { | ||||
|             if (!mapped.Contains(parameter.Id) && parameter.Property.SetMethod != null) | ||||
|             { | ||||
|                 parameter.Property.SetValue(settings, value); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return settings; | ||||
|     } | ||||
| } | ||||
| } | ||||
| @@ -1,44 +1,43 @@ | ||||
| using System; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| internal static class CommandPropertyBinder | ||||
| { | ||||
|     internal static class CommandPropertyBinder | ||||
|     public static CommandSettings CreateSettings(CommandValueLookup lookup, Type settingsType, ITypeResolver resolver) | ||||
|     { | ||||
|         public static CommandSettings CreateSettings(CommandValueLookup lookup, Type settingsType, ITypeResolver resolver) | ||||
|         var settings = CreateSettings(resolver, settingsType); | ||||
|  | ||||
|         foreach (var (parameter, value) in lookup) | ||||
|         { | ||||
|             var settings = CreateSettings(resolver, settingsType); | ||||
|  | ||||
|             foreach (var (parameter, value) in lookup) | ||||
|             if (value != default) | ||||
|             { | ||||
|                 if (value != default) | ||||
|                 { | ||||
|                     parameter.Property.SetValue(settings, value); | ||||
|                 } | ||||
|                 parameter.Property.SetValue(settings, value); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|             // Validate the settings. | ||||
|             var validationResult = settings.Validate(); | ||||
|             if (!validationResult.Successful) | ||||
|             { | ||||
|                 throw CommandRuntimeException.ValidationFailed(validationResult); | ||||
|             } | ||||
|         // Validate the settings. | ||||
|         var validationResult = settings.Validate(); | ||||
|         if (!validationResult.Successful) | ||||
|         { | ||||
|             throw CommandRuntimeException.ValidationFailed(validationResult); | ||||
|         } | ||||
|  | ||||
|         return settings; | ||||
|     } | ||||
|  | ||||
|     private static CommandSettings CreateSettings(ITypeResolver resolver, Type settingsType) | ||||
|     { | ||||
|         if (resolver.Resolve(settingsType) is CommandSettings settings) | ||||
|         { | ||||
|             return settings; | ||||
|         } | ||||
|  | ||||
|         private static CommandSettings CreateSettings(ITypeResolver resolver, Type settingsType) | ||||
|         if (Activator.CreateInstance(settingsType) is CommandSettings instance) | ||||
|         { | ||||
|             if (resolver.Resolve(settingsType) is CommandSettings settings) | ||||
|             { | ||||
|                 return settings; | ||||
|             } | ||||
|  | ||||
|             if (Activator.CreateInstance(settingsType) is CommandSettings instance) | ||||
|             { | ||||
|                 return instance; | ||||
|             } | ||||
|  | ||||
|             throw CommandParseException.CouldNotCreateSettings(settingsType); | ||||
|             return instance; | ||||
|         } | ||||
|  | ||||
|         throw CommandParseException.CouldNotCreateSettings(settingsType); | ||||
|     } | ||||
| } | ||||
| } | ||||
| @@ -1,118 +1,117 @@ | ||||
| using System; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| internal sealed class CommandValueBinder | ||||
| { | ||||
|     internal sealed class CommandValueBinder | ||||
|     private readonly CommandValueLookup _lookup; | ||||
|  | ||||
|     public CommandValueBinder(CommandValueLookup lookup) | ||||
|     { | ||||
|         private readonly CommandValueLookup _lookup; | ||||
|         _lookup = lookup; | ||||
|     } | ||||
|  | ||||
|         public CommandValueBinder(CommandValueLookup lookup) | ||||
|     public void Bind(CommandParameter parameter, ITypeResolver resolver, object? value) | ||||
|     { | ||||
|         if (parameter.ParameterKind == ParameterKind.Pair) | ||||
|         { | ||||
|             _lookup = lookup; | ||||
|             value = GetLookup(parameter, resolver, value); | ||||
|         } | ||||
|         else if (parameter.ParameterKind == ParameterKind.Vector) | ||||
|         { | ||||
|             value = GetArray(parameter, value); | ||||
|         } | ||||
|         else if (parameter.ParameterKind == ParameterKind.FlagWithValue) | ||||
|         { | ||||
|             value = GetFlag(parameter, value); | ||||
|         } | ||||
|  | ||||
|         public void Bind(CommandParameter parameter, ITypeResolver resolver, object? value) | ||||
|         _lookup.SetValue(parameter, value); | ||||
|     } | ||||
|  | ||||
|     private object GetLookup(CommandParameter parameter, ITypeResolver resolver, object? value) | ||||
|     { | ||||
|         var genericTypes = parameter.Property.PropertyType.GetGenericArguments(); | ||||
|  | ||||
|         var multimap = (IMultiMap?)_lookup.GetValue(parameter); | ||||
|         if (multimap == null) | ||||
|         { | ||||
|             if (parameter.ParameterKind == ParameterKind.Pair) | ||||
|             { | ||||
|                 value = GetLookup(parameter, resolver, value); | ||||
|             } | ||||
|             else if (parameter.ParameterKind == ParameterKind.Vector) | ||||
|             { | ||||
|                 value = GetArray(parameter, value); | ||||
|             } | ||||
|             else if (parameter.ParameterKind == ParameterKind.FlagWithValue) | ||||
|             { | ||||
|                 value = GetFlag(parameter, value); | ||||
|             } | ||||
|  | ||||
|             _lookup.SetValue(parameter, value); | ||||
|         } | ||||
|  | ||||
|         private object GetLookup(CommandParameter parameter, ITypeResolver resolver, object? value) | ||||
|         { | ||||
|             var genericTypes = parameter.Property.PropertyType.GetGenericArguments(); | ||||
|  | ||||
|             var multimap = (IMultiMap?)_lookup.GetValue(parameter); | ||||
|             multimap = Activator.CreateInstance(typeof(MultiMap<,>).MakeGenericType(genericTypes[0], genericTypes[1])) as IMultiMap; | ||||
|             if (multimap == null) | ||||
|             { | ||||
|                 multimap = Activator.CreateInstance(typeof(MultiMap<,>).MakeGenericType(genericTypes[0], genericTypes[1])) as IMultiMap; | ||||
|                 if (multimap == null) | ||||
|                 { | ||||
|                     throw new InvalidOperationException("Could not create multimap"); | ||||
|                 } | ||||
|                 throw new InvalidOperationException("Could not create multimap"); | ||||
|             } | ||||
|  | ||||
|             // Create deconstructor. | ||||
|             var deconstructorType = parameter.PairDeconstructor?.Type ?? typeof(DefaultPairDeconstructor); | ||||
|             if (!(resolver.Resolve(deconstructorType) is IPairDeconstructor deconstructor)) | ||||
|             { | ||||
|                 if (!(Activator.CreateInstance(deconstructorType) is IPairDeconstructor activatedDeconstructor)) | ||||
|                 { | ||||
|                     throw new InvalidOperationException($"Could not create pair deconstructor."); | ||||
|                 } | ||||
|  | ||||
|                 deconstructor = activatedDeconstructor; | ||||
|             } | ||||
|  | ||||
|             // Deconstruct and add to multimap. | ||||
|             var pair = deconstructor.Deconstruct(resolver, genericTypes[0], genericTypes[1], value as string); | ||||
|             if (pair.Key != null) | ||||
|             { | ||||
|                 multimap.Add(pair); | ||||
|             } | ||||
|  | ||||
|             return multimap; | ||||
|         } | ||||
|  | ||||
|         private object GetArray(CommandParameter parameter, object? value) | ||||
|         // Create deconstructor. | ||||
|         var deconstructorType = parameter.PairDeconstructor?.Type ?? typeof(DefaultPairDeconstructor); | ||||
|         if (!(resolver.Resolve(deconstructorType) is IPairDeconstructor deconstructor)) | ||||
|         { | ||||
|             // Add a new item to the array | ||||
|             var array = (Array?)_lookup.GetValue(parameter); | ||||
|             Array newArray; | ||||
|  | ||||
|             var elementType = parameter.Property.PropertyType.GetElementType(); | ||||
|             if (elementType == null) | ||||
|             if (!(Activator.CreateInstance(deconstructorType) is IPairDeconstructor activatedDeconstructor)) | ||||
|             { | ||||
|                 throw new InvalidOperationException("Could not get property type."); | ||||
|                 throw new InvalidOperationException($"Could not create pair deconstructor."); | ||||
|             } | ||||
|  | ||||
|             if (array == null) | ||||
|             { | ||||
|                 newArray = Array.CreateInstance(elementType, 1); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 newArray = Array.CreateInstance(elementType, array.Length + 1); | ||||
|                 array.CopyTo(newArray, 0); | ||||
|             } | ||||
|  | ||||
|             newArray.SetValue(value, newArray.Length - 1); | ||||
|             return newArray; | ||||
|             deconstructor = activatedDeconstructor; | ||||
|         } | ||||
|  | ||||
|         private object GetFlag(CommandParameter parameter, object? value) | ||||
|         // Deconstruct and add to multimap. | ||||
|         var pair = deconstructor.Deconstruct(resolver, genericTypes[0], genericTypes[1], value as string); | ||||
|         if (pair.Key != null) | ||||
|         { | ||||
|             var flagValue = (IFlagValue?)_lookup.GetValue(parameter); | ||||
|             multimap.Add(pair); | ||||
|         } | ||||
|  | ||||
|         return multimap; | ||||
|     } | ||||
|  | ||||
|     private object GetArray(CommandParameter parameter, object? value) | ||||
|     { | ||||
|         // Add a new item to the array | ||||
|         var array = (Array?)_lookup.GetValue(parameter); | ||||
|         Array newArray; | ||||
|  | ||||
|         var elementType = parameter.Property.PropertyType.GetElementType(); | ||||
|         if (elementType == null) | ||||
|         { | ||||
|             throw new InvalidOperationException("Could not get property type."); | ||||
|         } | ||||
|  | ||||
|         if (array == null) | ||||
|         { | ||||
|             newArray = Array.CreateInstance(elementType, 1); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             newArray = Array.CreateInstance(elementType, array.Length + 1); | ||||
|             array.CopyTo(newArray, 0); | ||||
|         } | ||||
|  | ||||
|         newArray.SetValue(value, newArray.Length - 1); | ||||
|         return newArray; | ||||
|     } | ||||
|  | ||||
|     private object GetFlag(CommandParameter parameter, object? value) | ||||
|     { | ||||
|         var flagValue = (IFlagValue?)_lookup.GetValue(parameter); | ||||
|         if (flagValue == null) | ||||
|         { | ||||
|             flagValue = (IFlagValue?)Activator.CreateInstance(parameter.ParameterType); | ||||
|             if (flagValue == null) | ||||
|             { | ||||
|                 flagValue = (IFlagValue?)Activator.CreateInstance(parameter.ParameterType); | ||||
|                 if (flagValue == null) | ||||
|                 { | ||||
|                     throw new InvalidOperationException("Could not create flag value."); | ||||
|                 } | ||||
|                 throw new InvalidOperationException("Could not create flag value."); | ||||
|             } | ||||
|  | ||||
|             if (value != null) | ||||
|             { | ||||
|                 // Null means set, but not with a valid value. | ||||
|                 flagValue.Value = value; | ||||
|             } | ||||
|  | ||||
|             // If the parameter was mapped, then it's set. | ||||
|             flagValue.IsSet = true; | ||||
|  | ||||
|             return flagValue; | ||||
|         } | ||||
|  | ||||
|         if (value != null) | ||||
|         { | ||||
|             // Null means set, but not with a valid value. | ||||
|             flagValue.Value = value; | ||||
|         } | ||||
|  | ||||
|         // If the parameter was mapped, then it's set. | ||||
|         flagValue.IsSet = true; | ||||
|  | ||||
|         return flagValue; | ||||
|     } | ||||
| } | ||||
| } | ||||
| @@ -3,61 +3,60 @@ using System.Collections; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| internal sealed class CommandValueLookup : IEnumerable<(CommandParameter Parameter, object? Value)> | ||||
| { | ||||
|     internal sealed class CommandValueLookup : IEnumerable<(CommandParameter Parameter, object? Value)> | ||||
|     private readonly Dictionary<Guid, (CommandParameter Parameter, object? Value)> _lookup; | ||||
|  | ||||
|     public CommandValueLookup() | ||||
|     { | ||||
|         private readonly Dictionary<Guid, (CommandParameter Parameter, object? Value)> _lookup; | ||||
|         _lookup = new Dictionary<Guid, (CommandParameter, object?)>(); | ||||
|     } | ||||
|  | ||||
|         public CommandValueLookup() | ||||
|     public IEnumerator<(CommandParameter Parameter, object? Value)> GetEnumerator() | ||||
|     { | ||||
|         foreach (var pair in _lookup) | ||||
|         { | ||||
|             _lookup = new Dictionary<Guid, (CommandParameter, object?)>(); | ||||
|             yield return pair.Value; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|         public IEnumerator<(CommandParameter Parameter, object? Value)> GetEnumerator() | ||||
|     public bool HasParameterWithName(string? name) | ||||
|     { | ||||
|         if (name == null) | ||||
|         { | ||||
|             foreach (var pair in _lookup) | ||||
|             { | ||||
|                 yield return pair.Value; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         public bool HasParameterWithName(string? name) | ||||
|         { | ||||
|             if (name == null) | ||||
|             { | ||||
|                 return false; | ||||
|             } | ||||
|  | ||||
|             return _lookup.Values.Any(pair => pair.Parameter.PropertyName.Equals(name, StringComparison.OrdinalIgnoreCase)); | ||||
|         } | ||||
|  | ||||
|         public bool TryGetParameterWithName(string? name, out (CommandParameter Parameter, object? Value) result) | ||||
|         { | ||||
|             if (HasParameterWithName(name)) | ||||
|             { | ||||
|                 result = _lookup.Values.FirstOrDefault(pair => pair.Parameter.PropertyName.Equals(name, StringComparison.OrdinalIgnoreCase)); | ||||
|                 return true; | ||||
|             } | ||||
|  | ||||
|             result = default; | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         public object? GetValue(CommandParameter parameter) | ||||
|         { | ||||
|             _lookup.TryGetValue(parameter.Id, out var result); | ||||
|             return result.Value; | ||||
|         } | ||||
|  | ||||
|         public void SetValue(CommandParameter parameter, object? value) | ||||
|         { | ||||
|             _lookup[parameter.Id] = (parameter, value); | ||||
|         } | ||||
|  | ||||
|         IEnumerator IEnumerable.GetEnumerator() | ||||
|         { | ||||
|             return GetEnumerator(); | ||||
|         } | ||||
|         return _lookup.Values.Any(pair => pair.Parameter.PropertyName.Equals(name, StringComparison.OrdinalIgnoreCase)); | ||||
|     } | ||||
| } | ||||
|  | ||||
|     public bool TryGetParameterWithName(string? name, out (CommandParameter Parameter, object? Value) result) | ||||
|     { | ||||
|         if (HasParameterWithName(name)) | ||||
|         { | ||||
|             result = _lookup.Values.FirstOrDefault(pair => pair.Parameter.PropertyName.Equals(name, StringComparison.OrdinalIgnoreCase)); | ||||
|             return true; | ||||
|         } | ||||
|  | ||||
|         result = default; | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     public object? GetValue(CommandParameter parameter) | ||||
|     { | ||||
|         _lookup.TryGetValue(parameter.Id, out var result); | ||||
|         return result.Value; | ||||
|     } | ||||
|  | ||||
|     public void SetValue(CommandParameter parameter, object? value) | ||||
|     { | ||||
|         _lookup[parameter.Id] = (parameter, value); | ||||
|     } | ||||
|  | ||||
|     IEnumerator IEnumerable.GetEnumerator() | ||||
|     { | ||||
|         return GetEnumerator(); | ||||
|     } | ||||
| } | ||||
| @@ -2,166 +2,165 @@ using System; | ||||
| using System.ComponentModel; | ||||
| using System.Diagnostics.CodeAnalysis; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| internal static class CommandValueResolver | ||||
| { | ||||
|     internal static class CommandValueResolver | ||||
|     public static CommandValueLookup GetParameterValues(CommandTree? tree, ITypeResolver resolver) | ||||
|     { | ||||
|         public static CommandValueLookup GetParameterValues(CommandTree? tree, ITypeResolver resolver) | ||||
|         var lookup = new CommandValueLookup(); | ||||
|         var binder = new CommandValueBinder(lookup); | ||||
|  | ||||
|         CommandValidator.ValidateRequiredParameters(tree); | ||||
|  | ||||
|         while (tree != null) | ||||
|         { | ||||
|             var lookup = new CommandValueLookup(); | ||||
|             var binder = new CommandValueBinder(lookup); | ||||
|  | ||||
|             CommandValidator.ValidateRequiredParameters(tree); | ||||
|  | ||||
|             while (tree != null) | ||||
|             // Process unmapped parameters. | ||||
|             foreach (var parameter in tree.Unmapped) | ||||
|             { | ||||
|                 // Process unmapped parameters. | ||||
|                 foreach (var parameter in tree.Unmapped) | ||||
|                 // Got a value provider? | ||||
|                 if (parameter.ValueProvider != null) | ||||
|                 { | ||||
|                     // Got a value provider? | ||||
|                     if (parameter.ValueProvider != null) | ||||
|                     var context = new CommandParameterContext(parameter, resolver, null); | ||||
|                     if (parameter.ValueProvider.TryGetValue(context, out var result)) | ||||
|                     { | ||||
|                         var context = new CommandParameterContext(parameter, resolver, null); | ||||
|                         if (parameter.ValueProvider.TryGetValue(context, out var result)) | ||||
|                         { | ||||
|                             result = ConvertValue(resolver, lookup, binder, parameter, result); | ||||
|                         result = ConvertValue(resolver, lookup, binder, parameter, result); | ||||
|  | ||||
|                             lookup.SetValue(parameter, result); | ||||
|                             CommandValidator.ValidateParameter(parameter, lookup, resolver); | ||||
|                             continue; | ||||
|                         } | ||||
|                         lookup.SetValue(parameter, result); | ||||
|                         CommandValidator.ValidateParameter(parameter, lookup, resolver); | ||||
|                         continue; | ||||
|                     } | ||||
|  | ||||
|                     if (parameter.IsFlagValue()) | ||||
|                     { | ||||
|                         // Set the flag value to an empty, not set instance. | ||||
|                         var instance = Activator.CreateInstance(parameter.ParameterType); | ||||
|                         lookup.SetValue(parameter, instance); | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         // Is this an option with a default value? | ||||
|                         if (parameter.DefaultValue != null) | ||||
|                         { | ||||
|                             var value = parameter.DefaultValue?.Value; | ||||
|                             value = ConvertValue(resolver, lookup, binder, parameter, value); | ||||
|  | ||||
|                             binder.Bind(parameter, resolver, value); | ||||
|                             CommandValidator.ValidateParameter(parameter, lookup, resolver); | ||||
|                         } | ||||
|                         else if (Nullable.GetUnderlyingType(parameter.ParameterType) != null || | ||||
|                                  !parameter.ParameterType.IsValueType) | ||||
|                         { | ||||
|                             lookup.SetValue(parameter, null); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 // Process mapped parameters. | ||||
|                 foreach (var mapped in tree.Mapped) | ||||
|                 { | ||||
|                     if (mapped.Parameter.WantRawValue) | ||||
|                     { | ||||
|                         // Just try to assign the raw value. | ||||
|                         binder.Bind(mapped.Parameter, resolver, mapped.Value); | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         if (mapped.Parameter.IsFlagValue() && mapped.Value == null) | ||||
|                         { | ||||
|                             if (mapped.Parameter is CommandOption option && option.DefaultValue != null) | ||||
|                             { | ||||
|                                 // Set the default value. | ||||
|                                 binder.Bind(mapped.Parameter, resolver, option.DefaultValue?.Value); | ||||
|                             } | ||||
|                             else | ||||
|                             { | ||||
|                                 // Set the flag but not the value. | ||||
|                                 binder.Bind(mapped.Parameter, resolver, null); | ||||
|                             } | ||||
|                         } | ||||
|                         else | ||||
|                         { | ||||
|                             var converter = GetConverter(lookup, binder, resolver, mapped.Parameter); | ||||
|                             if (converter == null) | ||||
|                             { | ||||
|                                 throw CommandRuntimeException.NoConverterFound(mapped.Parameter); | ||||
|                             } | ||||
|  | ||||
|                             // Assign the value to the parameter. | ||||
|                             binder.Bind(mapped.Parameter, resolver, converter.ConvertFromInvariantString(mapped.Value)); | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
|                     // Got a value provider? | ||||
|                     if (mapped.Parameter.ValueProvider != null) | ||||
|                     { | ||||
|                         var context = new CommandParameterContext(mapped.Parameter, resolver, mapped.Value); | ||||
|                         if (mapped.Parameter.ValueProvider.TryGetValue(context, out var result)) | ||||
|                         { | ||||
|                             lookup.SetValue(mapped.Parameter, result); | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
|                     CommandValidator.ValidateParameter(mapped.Parameter, lookup, resolver); | ||||
|                 } | ||||
|  | ||||
|                 tree = tree.Next; | ||||
|             } | ||||
|  | ||||
|             return lookup; | ||||
|         } | ||||
|  | ||||
|         private static object? ConvertValue(ITypeResolver resolver, CommandValueLookup lookup, CommandValueBinder binder, CommandParameter parameter, object? result) | ||||
|         { | ||||
|             if (result != null && result.GetType() != parameter.ParameterType) | ||||
|             { | ||||
|                 var converter = GetConverter(lookup, binder, resolver, parameter); | ||||
|                 if (converter != null) | ||||
|                 { | ||||
|                     result = converter.ConvertFrom(result); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             return result; | ||||
|         } | ||||
|  | ||||
|         [SuppressMessage("Style", "IDE0019:Use pattern matching", Justification = "It's OK")] | ||||
|         private static TypeConverter? GetConverter(CommandValueLookup lookup, CommandValueBinder binder, ITypeResolver resolver, CommandParameter parameter) | ||||
|         { | ||||
|             if (parameter.Converter == null) | ||||
|             { | ||||
|                 if (parameter.ParameterType.IsArray) | ||||
|                 { | ||||
|                     // Return a converter for each array item (not the whole array) | ||||
|                     return TypeDescriptor.GetConverter(parameter.ParameterType.GetElementType()); | ||||
|                 } | ||||
|  | ||||
|                 if (parameter.IsFlagValue()) | ||||
|                 { | ||||
|                     // Is the optional value instanciated? | ||||
|                     var value = lookup.GetValue(parameter) as IFlagValue; | ||||
|                     if (value == null) | ||||
|                     { | ||||
|                         // Try to assign it with a null value. | ||||
|                         // This will create the optional value instance without a value. | ||||
|                         binder.Bind(parameter, resolver, null); | ||||
|                         value = lookup.GetValue(parameter) as IFlagValue; | ||||
|                         if (value == null) | ||||
|                         { | ||||
|                             throw new InvalidOperationException("Could not intialize optional value."); | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
|                     // Return a converter for the flag element type. | ||||
|                     return TypeDescriptor.GetConverter(value.Type); | ||||
|                     // Set the flag value to an empty, not set instance. | ||||
|                     var instance = Activator.CreateInstance(parameter.ParameterType); | ||||
|                     lookup.SetValue(parameter, instance); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     // Is this an option with a default value? | ||||
|                     if (parameter.DefaultValue != null) | ||||
|                     { | ||||
|                         var value = parameter.DefaultValue?.Value; | ||||
|                         value = ConvertValue(resolver, lookup, binder, parameter, value); | ||||
|  | ||||
|                 return TypeDescriptor.GetConverter(parameter.ParameterType); | ||||
|                         binder.Bind(parameter, resolver, value); | ||||
|                         CommandValidator.ValidateParameter(parameter, lookup, resolver); | ||||
|                     } | ||||
|                     else if (Nullable.GetUnderlyingType(parameter.ParameterType) != null || | ||||
|                              !parameter.ParameterType.IsValueType) | ||||
|                     { | ||||
|                         lookup.SetValue(parameter, null); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             var type = Type.GetType(parameter.Converter.ConverterTypeName); | ||||
|             return resolver.Resolve(type) as TypeConverter; | ||||
|             // Process mapped parameters. | ||||
|             foreach (var mapped in tree.Mapped) | ||||
|             { | ||||
|                 if (mapped.Parameter.WantRawValue) | ||||
|                 { | ||||
|                     // Just try to assign the raw value. | ||||
|                     binder.Bind(mapped.Parameter, resolver, mapped.Value); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     if (mapped.Parameter.IsFlagValue() && mapped.Value == null) | ||||
|                     { | ||||
|                         if (mapped.Parameter is CommandOption option && option.DefaultValue != null) | ||||
|                         { | ||||
|                             // Set the default value. | ||||
|                             binder.Bind(mapped.Parameter, resolver, option.DefaultValue?.Value); | ||||
|                         } | ||||
|                         else | ||||
|                         { | ||||
|                             // Set the flag but not the value. | ||||
|                             binder.Bind(mapped.Parameter, resolver, null); | ||||
|                         } | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         var converter = GetConverter(lookup, binder, resolver, mapped.Parameter); | ||||
|                         if (converter == null) | ||||
|                         { | ||||
|                             throw CommandRuntimeException.NoConverterFound(mapped.Parameter); | ||||
|                         } | ||||
|  | ||||
|                         // Assign the value to the parameter. | ||||
|                         binder.Bind(mapped.Parameter, resolver, converter.ConvertFromInvariantString(mapped.Value)); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 // Got a value provider? | ||||
|                 if (mapped.Parameter.ValueProvider != null) | ||||
|                 { | ||||
|                     var context = new CommandParameterContext(mapped.Parameter, resolver, mapped.Value); | ||||
|                     if (mapped.Parameter.ValueProvider.TryGetValue(context, out var result)) | ||||
|                     { | ||||
|                         lookup.SetValue(mapped.Parameter, result); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 CommandValidator.ValidateParameter(mapped.Parameter, lookup, resolver); | ||||
|             } | ||||
|  | ||||
|             tree = tree.Next; | ||||
|         } | ||||
|  | ||||
|         return lookup; | ||||
|     } | ||||
| } | ||||
|  | ||||
|     private static object? ConvertValue(ITypeResolver resolver, CommandValueLookup lookup, CommandValueBinder binder, CommandParameter parameter, object? result) | ||||
|     { | ||||
|         if (result != null && result.GetType() != parameter.ParameterType) | ||||
|         { | ||||
|             var converter = GetConverter(lookup, binder, resolver, parameter); | ||||
|             if (converter != null) | ||||
|             { | ||||
|                 result = converter.ConvertFrom(result); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return result; | ||||
|     } | ||||
|  | ||||
|     [SuppressMessage("Style", "IDE0019:Use pattern matching", Justification = "It's OK")] | ||||
|     private static TypeConverter? GetConverter(CommandValueLookup lookup, CommandValueBinder binder, ITypeResolver resolver, CommandParameter parameter) | ||||
|     { | ||||
|         if (parameter.Converter == null) | ||||
|         { | ||||
|             if (parameter.ParameterType.IsArray) | ||||
|             { | ||||
|                 // Return a converter for each array item (not the whole array) | ||||
|                 return TypeDescriptor.GetConverter(parameter.ParameterType.GetElementType()); | ||||
|             } | ||||
|  | ||||
|             if (parameter.IsFlagValue()) | ||||
|             { | ||||
|                 // Is the optional value instanciated? | ||||
|                 var value = lookup.GetValue(parameter) as IFlagValue; | ||||
|                 if (value == null) | ||||
|                 { | ||||
|                     // Try to assign it with a null value. | ||||
|                     // This will create the optional value instance without a value. | ||||
|                     binder.Bind(parameter, resolver, null); | ||||
|                     value = lookup.GetValue(parameter) as IFlagValue; | ||||
|                     if (value == null) | ||||
|                     { | ||||
|                         throw new InvalidOperationException("Could not intialize optional value."); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 // Return a converter for the flag element type. | ||||
|                 return TypeDescriptor.GetConverter(value.Type); | ||||
|             } | ||||
|  | ||||
|             return TypeDescriptor.GetConverter(parameter.ParameterType); | ||||
|         } | ||||
|  | ||||
|         var type = Type.GetType(parameter.Converter.ConverterTypeName); | ||||
|         return resolver.Resolve(type) as TypeConverter; | ||||
|     } | ||||
| } | ||||
| @@ -1,14 +1,13 @@ | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| /// <summary> | ||||
| /// Representation of a multi map. | ||||
| /// </summary> | ||||
| internal interface IMultiMap | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Representation of a multi map. | ||||
|     /// Adds a key and a value to the multi map. | ||||
|     /// </summary> | ||||
|     internal interface IMultiMap | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Adds a key and a value to the multi map. | ||||
|         /// </summary> | ||||
|         /// <param name="pair">The pair to add.</param> | ||||
|         void Add((object? Key, object? Value) pair); | ||||
|     } | ||||
| } | ||||
|     /// <param name="pair">The pair to add.</param> | ||||
|     void Add((object? Key, object? Value) pair); | ||||
| } | ||||
| @@ -4,172 +4,171 @@ using System.Collections.Generic; | ||||
| using System.Diagnostics.CodeAnalysis; | ||||
| using System.Linq; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| [SuppressMessage("Performance", "CA1812: Avoid uninstantiated internal classes")] | ||||
| internal sealed class MultiMap<TKey, TValue> : IMultiMap, ILookup<TKey, TValue>, IDictionary<TKey, TValue>, IReadOnlyDictionary<TKey, TValue> | ||||
|     where TKey : notnull | ||||
| { | ||||
|     [SuppressMessage("Performance", "CA1812: Avoid uninstantiated internal classes")] | ||||
|     internal sealed class MultiMap<TKey, TValue> : IMultiMap, ILookup<TKey, TValue>, IDictionary<TKey, TValue>, IReadOnlyDictionary<TKey, TValue> | ||||
|         where TKey : notnull | ||||
|     private readonly IDictionary<TKey, MultiMapGrouping> _lookup; | ||||
|     private readonly IDictionary<TKey, TValue> _dictionary; | ||||
|  | ||||
|     public int Count => _lookup.Count; | ||||
|  | ||||
|     public bool IsReadOnly => false; | ||||
|  | ||||
|     public ICollection<TKey> Keys => _lookup.Keys; | ||||
|  | ||||
|     public ICollection<TValue> Values => _dictionary.Values; | ||||
|  | ||||
|     IEnumerable<TKey> IReadOnlyDictionary<TKey, TValue>.Keys => _lookup.Keys; | ||||
|  | ||||
|     IEnumerable<TValue> IReadOnlyDictionary<TKey, TValue>.Values => _dictionary.Values; | ||||
|  | ||||
|     TValue IReadOnlyDictionary<TKey, TValue>.this[TKey key] => _dictionary[key]; | ||||
|  | ||||
|     TValue IDictionary<TKey, TValue>.this[TKey key] | ||||
|     { | ||||
|         private readonly IDictionary<TKey, MultiMapGrouping> _lookup; | ||||
|         private readonly IDictionary<TKey, TValue> _dictionary; | ||||
|  | ||||
|         public int Count => _lookup.Count; | ||||
|  | ||||
|         public bool IsReadOnly => false; | ||||
|  | ||||
|         public ICollection<TKey> Keys => _lookup.Keys; | ||||
|  | ||||
|         public ICollection<TValue> Values => _dictionary.Values; | ||||
|  | ||||
|         IEnumerable<TKey> IReadOnlyDictionary<TKey, TValue>.Keys => _lookup.Keys; | ||||
|  | ||||
|         IEnumerable<TValue> IReadOnlyDictionary<TKey, TValue>.Values => _dictionary.Values; | ||||
|  | ||||
|         TValue IReadOnlyDictionary<TKey, TValue>.this[TKey key] => _dictionary[key]; | ||||
|  | ||||
|         TValue IDictionary<TKey, TValue>.this[TKey key] | ||||
|         get | ||||
|         { | ||||
|             get | ||||
|             return _dictionary[key]; | ||||
|         } | ||||
|         set | ||||
|         { | ||||
|             Add(key, value); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public IEnumerable<TValue> this[TKey key] | ||||
|     { | ||||
|         get | ||||
|         { | ||||
|             if (_lookup.TryGetValue(key, out var group)) | ||||
|             { | ||||
|                 return _dictionary[key]; | ||||
|             } | ||||
|             set | ||||
|             { | ||||
|                 Add(key, value); | ||||
|                 return group; | ||||
|             } | ||||
|  | ||||
|             return Array.Empty<TValue>(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public MultiMap() | ||||
|     { | ||||
|         _lookup = new Dictionary<TKey, MultiMapGrouping>(); | ||||
|         _dictionary = new Dictionary<TKey, TValue>(); | ||||
|     } | ||||
|  | ||||
|     private sealed class MultiMapGrouping : IGrouping<TKey, TValue> | ||||
|     { | ||||
|         private readonly List<TValue> _items; | ||||
|  | ||||
|         public TKey Key { get; } | ||||
|  | ||||
|         public MultiMapGrouping(TKey key, List<TValue> items) | ||||
|         { | ||||
|             Key = key; | ||||
|             _items = items; | ||||
|         } | ||||
|  | ||||
|         public IEnumerable<TValue> this[TKey key] | ||||
|         public void Add(TValue value) | ||||
|         { | ||||
|             get | ||||
|             { | ||||
|                 if (_lookup.TryGetValue(key, out var group)) | ||||
|                 { | ||||
|                     return group; | ||||
|                 } | ||||
|  | ||||
|                 return Array.Empty<TValue>(); | ||||
|             } | ||||
|             _items.Add(value); | ||||
|         } | ||||
|  | ||||
|         public MultiMap() | ||||
|         public IEnumerator<TValue> GetEnumerator() | ||||
|         { | ||||
|             _lookup = new Dictionary<TKey, MultiMapGrouping>(); | ||||
|             _dictionary = new Dictionary<TKey, TValue>(); | ||||
|         } | ||||
|  | ||||
|         private sealed class MultiMapGrouping : IGrouping<TKey, TValue> | ||||
|         { | ||||
|             private readonly List<TValue> _items; | ||||
|  | ||||
|             public TKey Key { get; } | ||||
|  | ||||
|             public MultiMapGrouping(TKey key, List<TValue> items) | ||||
|             { | ||||
|                 Key = key; | ||||
|                 _items = items; | ||||
|             } | ||||
|  | ||||
|             public void Add(TValue value) | ||||
|             { | ||||
|                 _items.Add(value); | ||||
|             } | ||||
|  | ||||
|             public IEnumerator<TValue> GetEnumerator() | ||||
|             { | ||||
|                 return _items.GetEnumerator(); | ||||
|             } | ||||
|  | ||||
|             IEnumerator IEnumerable.GetEnumerator() | ||||
|             { | ||||
|                 return GetEnumerator(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         public bool Contains(TKey key) | ||||
|         { | ||||
|             return _lookup.ContainsKey(key); | ||||
|         } | ||||
|  | ||||
|         public IEnumerator<IGrouping<TKey, TValue>> GetEnumerator() | ||||
|         { | ||||
|             foreach (var group in _lookup.Values) | ||||
|             { | ||||
|                 yield return group; | ||||
|             } | ||||
|             return _items.GetEnumerator(); | ||||
|         } | ||||
|  | ||||
|         IEnumerator IEnumerable.GetEnumerator() | ||||
|         { | ||||
|             return GetEnumerator(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|         public void Add(TKey key, TValue value) | ||||
|     public bool Contains(TKey key) | ||||
|     { | ||||
|         return _lookup.ContainsKey(key); | ||||
|     } | ||||
|  | ||||
|     public IEnumerator<IGrouping<TKey, TValue>> GetEnumerator() | ||||
|     { | ||||
|         foreach (var group in _lookup.Values) | ||||
|         { | ||||
|             if (!_lookup.ContainsKey(key)) | ||||
|             { | ||||
|                 _lookup[key] = new MultiMapGrouping(key, new List<TValue>()); | ||||
|             } | ||||
|  | ||||
|             _lookup[key].Add(value); | ||||
|             _dictionary[key] = value; | ||||
|         } | ||||
|  | ||||
|         public bool ContainsKey(TKey key) | ||||
|         { | ||||
|             return Contains(key); | ||||
|         } | ||||
|  | ||||
|         public bool Remove(TKey key) | ||||
|         { | ||||
|             return _lookup.Remove(key); | ||||
|         } | ||||
|  | ||||
|         public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) | ||||
|         { | ||||
|             return _dictionary.TryGetValue(key, out value); | ||||
|         } | ||||
|  | ||||
|         public void Add(KeyValuePair<TKey, TValue> item) | ||||
|         { | ||||
|             Add(item.Key, item.Value); | ||||
|         } | ||||
|  | ||||
|         public void Clear() | ||||
|         { | ||||
|             _lookup.Clear(); | ||||
|         } | ||||
|  | ||||
|         public bool Contains(KeyValuePair<TKey, TValue> item) | ||||
|         { | ||||
|             return Contains(item.Key); | ||||
|         } | ||||
|  | ||||
|         public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) | ||||
|         { | ||||
|             _dictionary.CopyTo(array, arrayIndex); | ||||
|         } | ||||
|  | ||||
|         public bool Remove(KeyValuePair<TKey, TValue> item) | ||||
|         { | ||||
|             return Remove(item.Key); | ||||
|         } | ||||
|  | ||||
|         IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator() | ||||
|         { | ||||
|             return _dictionary.GetEnumerator(); | ||||
|         } | ||||
|  | ||||
|         public void Add((object? Key, object? Value) pair) | ||||
|         { | ||||
|             if (pair.Key != null) | ||||
|             { | ||||
| #pragma warning disable CS8604 // Possible null reference argument of value. | ||||
| #pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. | ||||
|                 Add((TKey)pair.Key, (TValue)pair.Value); | ||||
| #pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type. | ||||
| #pragma warning restore CS8604 // Possible null reference argument of value. | ||||
|             } | ||||
|             yield return group; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
|     IEnumerator IEnumerable.GetEnumerator() | ||||
|     { | ||||
|         return GetEnumerator(); | ||||
|     } | ||||
|  | ||||
|     public void Add(TKey key, TValue value) | ||||
|     { | ||||
|         if (!_lookup.ContainsKey(key)) | ||||
|         { | ||||
|             _lookup[key] = new MultiMapGrouping(key, new List<TValue>()); | ||||
|         } | ||||
|  | ||||
|         _lookup[key].Add(value); | ||||
|         _dictionary[key] = value; | ||||
|     } | ||||
|  | ||||
|     public bool ContainsKey(TKey key) | ||||
|     { | ||||
|         return Contains(key); | ||||
|     } | ||||
|  | ||||
|     public bool Remove(TKey key) | ||||
|     { | ||||
|         return _lookup.Remove(key); | ||||
|     } | ||||
|  | ||||
|     public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) | ||||
|     { | ||||
|         return _dictionary.TryGetValue(key, out value); | ||||
|     } | ||||
|  | ||||
|     public void Add(KeyValuePair<TKey, TValue> item) | ||||
|     { | ||||
|         Add(item.Key, item.Value); | ||||
|     } | ||||
|  | ||||
|     public void Clear() | ||||
|     { | ||||
|         _lookup.Clear(); | ||||
|     } | ||||
|  | ||||
|     public bool Contains(KeyValuePair<TKey, TValue> item) | ||||
|     { | ||||
|         return Contains(item.Key); | ||||
|     } | ||||
|  | ||||
|     public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) | ||||
|     { | ||||
|         _dictionary.CopyTo(array, arrayIndex); | ||||
|     } | ||||
|  | ||||
|     public bool Remove(KeyValuePair<TKey, TValue> item) | ||||
|     { | ||||
|         return Remove(item.Key); | ||||
|     } | ||||
|  | ||||
|     IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator() | ||||
|     { | ||||
|         return _dictionary.GetEnumerator(); | ||||
|     } | ||||
|  | ||||
|     public void Add((object? Key, object? Value) pair) | ||||
|     { | ||||
|         if (pair.Key != null) | ||||
|         { | ||||
| #pragma warning disable CS8604 // Possible null reference argument of value. | ||||
| #pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. | ||||
|             Add((TKey)pair.Key, (TValue)pair.Value); | ||||
| #pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type. | ||||
| #pragma warning restore CS8604 // Possible null reference argument of value. | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,31 +1,30 @@ | ||||
| using System; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| { | ||||
|     internal static class CommandBinder | ||||
|     { | ||||
|         public static CommandSettings Bind(CommandTree? tree, Type settingsType, ITypeResolver resolver) | ||||
|         { | ||||
|             var lookup = CommandValueResolver.GetParameterValues(tree, resolver); | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
|             // Got a constructor with at least one name corresponding to a settings? | ||||
|             foreach (var constructor in settingsType.GetConstructors()) | ||||
| internal static class CommandBinder | ||||
| { | ||||
|     public static CommandSettings Bind(CommandTree? tree, Type settingsType, ITypeResolver resolver) | ||||
|     { | ||||
|         var lookup = CommandValueResolver.GetParameterValues(tree, resolver); | ||||
|  | ||||
|         // Got a constructor with at least one name corresponding to a settings? | ||||
|         foreach (var constructor in settingsType.GetConstructors()) | ||||
|         { | ||||
|             var parameters = constructor.GetParameters(); | ||||
|             if (parameters.Length > 0) | ||||
|             { | ||||
|                 var parameters = constructor.GetParameters(); | ||||
|                 if (parameters.Length > 0) | ||||
|                 foreach (var parameter in parameters) | ||||
|                 { | ||||
|                     foreach (var parameter in parameters) | ||||
|                     if (lookup.HasParameterWithName(parameter?.Name)) | ||||
|                     { | ||||
|                         if (lookup.HasParameterWithName(parameter?.Name)) | ||||
|                         { | ||||
|                             // Use constructor injection. | ||||
|                             return CommandConstructorBinder.CreateSettings(lookup, constructor, resolver); | ||||
|                         } | ||||
|                         // Use constructor injection. | ||||
|                         return CommandConstructorBinder.CreateSettings(lookup, constructor, resolver); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             return CommandPropertyBinder.CreateSettings(lookup, settingsType, resolver); | ||||
|         } | ||||
|  | ||||
|         return CommandPropertyBinder.CreateSettings(lookup, settingsType, resolver); | ||||
|     } | ||||
| } | ||||
| } | ||||
| @@ -4,115 +4,114 @@ using System.Linq; | ||||
| using System.Reflection; | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| { | ||||
|     internal sealed class CommandExecutor | ||||
|     { | ||||
|         private readonly ITypeRegistrar _registrar; | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
|         public CommandExecutor(ITypeRegistrar registrar) | ||||
| internal sealed class CommandExecutor | ||||
| { | ||||
|     private readonly ITypeRegistrar _registrar; | ||||
|  | ||||
|     public CommandExecutor(ITypeRegistrar registrar) | ||||
|     { | ||||
|         _registrar = registrar ?? throw new ArgumentNullException(nameof(registrar)); | ||||
|         _registrar.Register(typeof(DefaultPairDeconstructor), typeof(DefaultPairDeconstructor)); | ||||
|     } | ||||
|  | ||||
|     public async Task<int> Execute(IConfiguration configuration, IEnumerable<string> args) | ||||
|     { | ||||
|         if (configuration == null) | ||||
|         { | ||||
|             _registrar = registrar ?? throw new ArgumentNullException(nameof(registrar)); | ||||
|             _registrar.Register(typeof(DefaultPairDeconstructor), typeof(DefaultPairDeconstructor)); | ||||
|             throw new ArgumentNullException(nameof(configuration)); | ||||
|         } | ||||
|  | ||||
|         public async Task<int> Execute(IConfiguration configuration, IEnumerable<string> args) | ||||
|         _registrar.RegisterInstance(typeof(IConfiguration), configuration); | ||||
|         _registrar.RegisterLazy(typeof(IAnsiConsole), () => configuration.Settings.Console.GetConsole()); | ||||
|  | ||||
|         // Create the command model. | ||||
|         var model = CommandModelBuilder.Build(configuration); | ||||
|         _registrar.RegisterInstance(typeof(CommandModel), model); | ||||
|         _registrar.RegisterDependencies(model); | ||||
|  | ||||
|         // No default command? | ||||
|         if (model.DefaultCommand == null) | ||||
|         { | ||||
|             if (configuration == null) | ||||
|             // Got at least one argument? | ||||
|             var firstArgument = args.FirstOrDefault(); | ||||
|             if (firstArgument != null) | ||||
|             { | ||||
|                 throw new ArgumentNullException(nameof(configuration)); | ||||
|             } | ||||
|  | ||||
|             _registrar.RegisterInstance(typeof(IConfiguration), configuration); | ||||
|             _registrar.RegisterLazy(typeof(IAnsiConsole), () => configuration.Settings.Console.GetConsole()); | ||||
|  | ||||
|             // Create the command model. | ||||
|             var model = CommandModelBuilder.Build(configuration); | ||||
|             _registrar.RegisterInstance(typeof(CommandModel), model); | ||||
|             _registrar.RegisterDependencies(model); | ||||
|  | ||||
|             // No default command? | ||||
|             if (model.DefaultCommand == null) | ||||
|             { | ||||
|                 // Got at least one argument? | ||||
|                 var firstArgument = args.FirstOrDefault(); | ||||
|                 if (firstArgument != null) | ||||
|                 // Asking for version? Kind of a hack, but it's alright. | ||||
|                 // We should probably make this a bit better in the future. | ||||
|                 if (firstArgument.Equals("--version", StringComparison.OrdinalIgnoreCase) || | ||||
|                     firstArgument.Equals("-v", StringComparison.OrdinalIgnoreCase)) | ||||
|                 { | ||||
|                     // Asking for version? Kind of a hack, but it's alright. | ||||
|                     // We should probably make this a bit better in the future. | ||||
|                     if (firstArgument.Equals("--version", StringComparison.OrdinalIgnoreCase) || | ||||
|                         firstArgument.Equals("-v", StringComparison.OrdinalIgnoreCase)) | ||||
|                     { | ||||
|                         var console = configuration.Settings.Console.GetConsole(); | ||||
|                         console.WriteLine(ResolveApplicationVersion(configuration)); | ||||
|                         return 0; | ||||
|                     } | ||||
|                     var console = configuration.Settings.Console.GetConsole(); | ||||
|                     console.WriteLine(ResolveApplicationVersion(configuration)); | ||||
|                     return 0; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             // Parse and map the model against the arguments. | ||||
|             var parser = new CommandTreeParser(model, configuration.Settings); | ||||
|             var parsedResult = parser.Parse(args); | ||||
|             _registrar.RegisterInstance(typeof(CommandTreeParserResult), parsedResult); | ||||
|  | ||||
|             // Currently the root? | ||||
|             if (parsedResult.Tree == null) | ||||
|             { | ||||
|                 // Display help. | ||||
|                 configuration.Settings.Console.SafeRender(HelpWriter.Write(model)); | ||||
|                 return 0; | ||||
|             } | ||||
|  | ||||
|             // Get the command to execute. | ||||
|             var leaf = parsedResult.Tree.GetLeafCommand(); | ||||
|             if (leaf.Command.IsBranch || leaf.ShowHelp) | ||||
|             { | ||||
|                 // Branches can't be executed. Show help. | ||||
|                 configuration.Settings.Console.SafeRender(HelpWriter.WriteCommand(model, leaf.Command)); | ||||
|                 return leaf.ShowHelp ? 0 : 1; | ||||
|             } | ||||
|  | ||||
|             // Register the arguments with the container. | ||||
|             _registrar.RegisterInstance(typeof(IRemainingArguments), parsedResult.Remaining); | ||||
|  | ||||
|             // Create the resolver and the context. | ||||
|             using (var resolver = new TypeResolverAdapter(_registrar.Build())) | ||||
|             { | ||||
|                 var context = new CommandContext(parsedResult.Remaining, leaf.Command.Name, leaf.Command.Data); | ||||
|  | ||||
|                 // Execute the command tree. | ||||
|                 return await Execute(leaf, parsedResult.Tree, context, resolver, configuration).ConfigureAwait(false); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         private static string ResolveApplicationVersion(IConfiguration configuration) | ||||
|         // Parse and map the model against the arguments. | ||||
|         var parser = new CommandTreeParser(model, configuration.Settings); | ||||
|         var parsedResult = parser.Parse(args); | ||||
|         _registrar.RegisterInstance(typeof(CommandTreeParserResult), parsedResult); | ||||
|  | ||||
|         // Currently the root? | ||||
|         if (parsedResult.Tree == null) | ||||
|         { | ||||
|             return | ||||
|                 configuration.Settings.ApplicationVersion ?? // potential override | ||||
|                 VersionHelper.GetVersion(Assembly.GetEntryAssembly()); | ||||
|             // Display help. | ||||
|             configuration.Settings.Console.SafeRender(HelpWriter.Write(model)); | ||||
|             return 0; | ||||
|         } | ||||
|  | ||||
|         private static Task<int> Execute( | ||||
|             CommandTree leaf, | ||||
|             CommandTree tree, | ||||
|             CommandContext context, | ||||
|             ITypeResolver resolver, | ||||
|             IConfiguration configuration) | ||||
|         // Get the command to execute. | ||||
|         var leaf = parsedResult.Tree.GetLeafCommand(); | ||||
|         if (leaf.Command.IsBranch || leaf.ShowHelp) | ||||
|         { | ||||
|             // Bind the command tree against the settings. | ||||
|             var settings = CommandBinder.Bind(tree, leaf.Command.SettingsType, resolver); | ||||
|             configuration.Settings.Interceptor?.Intercept(context, settings); | ||||
|             // Branches can't be executed. Show help. | ||||
|             configuration.Settings.Console.SafeRender(HelpWriter.WriteCommand(model, leaf.Command)); | ||||
|             return leaf.ShowHelp ? 0 : 1; | ||||
|         } | ||||
|  | ||||
|             // Create and validate the command. | ||||
|             var command = leaf.CreateCommand(resolver); | ||||
|             var validationResult = command.Validate(context, settings); | ||||
|             if (!validationResult.Successful) | ||||
|             { | ||||
|                 throw CommandRuntimeException.ValidationFailed(validationResult); | ||||
|             } | ||||
|         // Register the arguments with the container. | ||||
|         _registrar.RegisterInstance(typeof(IRemainingArguments), parsedResult.Remaining); | ||||
|  | ||||
|             // Execute the command. | ||||
|             return command.Execute(context, settings); | ||||
|         // Create the resolver and the context. | ||||
|         using (var resolver = new TypeResolverAdapter(_registrar.Build())) | ||||
|         { | ||||
|             var context = new CommandContext(parsedResult.Remaining, leaf.Command.Name, leaf.Command.Data); | ||||
|  | ||||
|             // Execute the command tree. | ||||
|             return await Execute(leaf, parsedResult.Tree, context, resolver, configuration).ConfigureAwait(false); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
|     private static string ResolveApplicationVersion(IConfiguration configuration) | ||||
|     { | ||||
|         return | ||||
|             configuration.Settings.ApplicationVersion ?? // potential override | ||||
|             VersionHelper.GetVersion(Assembly.GetEntryAssembly()); | ||||
|     } | ||||
|  | ||||
|     private static Task<int> Execute( | ||||
|         CommandTree leaf, | ||||
|         CommandTree tree, | ||||
|         CommandContext context, | ||||
|         ITypeResolver resolver, | ||||
|         IConfiguration configuration) | ||||
|     { | ||||
|         // Bind the command tree against the settings. | ||||
|         var settings = CommandBinder.Bind(tree, leaf.Command.SettingsType, resolver); | ||||
|         configuration.Settings.Interceptor?.Intercept(context, settings); | ||||
|  | ||||
|         // Create and validate the command. | ||||
|         var command = leaf.CreateCommand(resolver); | ||||
|         var validationResult = command.Validate(context, settings); | ||||
|         if (!validationResult.Successful) | ||||
|         { | ||||
|             throw CommandRuntimeException.ValidationFailed(validationResult); | ||||
|         } | ||||
|  | ||||
|         // Execute the command. | ||||
|         return command.Execute(context, settings); | ||||
|     } | ||||
| } | ||||
| @@ -1,8 +1,7 @@ | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| internal enum CommandPart | ||||
| { | ||||
|     internal enum CommandPart | ||||
|     { | ||||
|         CommandName, | ||||
|         LongOption, | ||||
|     } | ||||
| } | ||||
|     CommandName, | ||||
|     LongOption, | ||||
| } | ||||
| @@ -1,77 +1,76 @@ | ||||
| using System; | ||||
| using System.Linq; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| internal static class CommandSuggestor | ||||
| { | ||||
|     internal static class CommandSuggestor | ||||
|     private const float SmallestDistance = 2f; | ||||
|  | ||||
|     public static CommandInfo? Suggest(CommandModel model, CommandInfo? command, string name) | ||||
|     { | ||||
|         private const float SmallestDistance = 2f; | ||||
|         var result = (CommandInfo?)null; | ||||
|  | ||||
|         public static CommandInfo? Suggest(CommandModel model, CommandInfo? command, string name) | ||||
|         var container = command ?? (ICommandContainer)model; | ||||
|         if (command?.IsDefaultCommand ?? false) | ||||
|         { | ||||
|             var result = (CommandInfo?)null; | ||||
|  | ||||
|             var container = command ?? (ICommandContainer)model; | ||||
|             if (command?.IsDefaultCommand ?? false) | ||||
|             { | ||||
|                 // Default commands have no children, | ||||
|                 // so use the root commands here. | ||||
|                 container = model; | ||||
|             } | ||||
|  | ||||
|             var score = float.MaxValue; | ||||
|             foreach (var child in container.Commands.Where(x => !x.IsHidden)) | ||||
|             { | ||||
|                 var temp = Score(child.Name, name); | ||||
|                 if (temp < score) | ||||
|                 { | ||||
|                     score = temp; | ||||
|                     result = child; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             if (score <= SmallestDistance) | ||||
|             { | ||||
|                 return result; | ||||
|             } | ||||
|  | ||||
|             return null; | ||||
|             // Default commands have no children, | ||||
|             // so use the root commands here. | ||||
|             container = model; | ||||
|         } | ||||
|  | ||||
|         private static float Score(string source, string target) | ||||
|         var score = float.MaxValue; | ||||
|         foreach (var child in container.Commands.Where(x => !x.IsHidden)) | ||||
|         { | ||||
|             source = source.ToUpperInvariant(); | ||||
|             target = target.ToUpperInvariant(); | ||||
|  | ||||
|             var n = source.Length; | ||||
|             var m = target.Length; | ||||
|  | ||||
|             if (n == 0) | ||||
|             var temp = Score(child.Name, name); | ||||
|             if (temp < score) | ||||
|             { | ||||
|                 return m; | ||||
|                 score = temp; | ||||
|                 result = child; | ||||
|             } | ||||
|  | ||||
|             if (m == 0) | ||||
|             { | ||||
|                 return n; | ||||
|             } | ||||
|  | ||||
|             var d = new int[n + 1, m + 1]; | ||||
|             Enumerable.Range(0, n + 1).ToList().ForEach(i => d[i, 0] = i); | ||||
|             Enumerable.Range(0, m + 1).ToList().ForEach(i => d[0, i] = i); | ||||
|  | ||||
|             for (var sourceIndex = 1; sourceIndex <= n; sourceIndex++) | ||||
|             { | ||||
|                 for (var targetIndex = 1; targetIndex <= m; targetIndex++) | ||||
|                 { | ||||
|                     var cost = (target[targetIndex - 1] == source[sourceIndex - 1]) ? 0 : 1; | ||||
|                     d[sourceIndex, targetIndex] = Math.Min( | ||||
|                         Math.Min(d[sourceIndex - 1, targetIndex] + 1, d[sourceIndex, targetIndex - 1] + 1), | ||||
|                         d[sourceIndex - 1, targetIndex - 1] + cost); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             return d[n, m]; | ||||
|         } | ||||
|  | ||||
|         if (score <= SmallestDistance) | ||||
|         { | ||||
|             return result; | ||||
|         } | ||||
|  | ||||
|         return null; | ||||
|     } | ||||
| } | ||||
|  | ||||
|     private static float Score(string source, string target) | ||||
|     { | ||||
|         source = source.ToUpperInvariant(); | ||||
|         target = target.ToUpperInvariant(); | ||||
|  | ||||
|         var n = source.Length; | ||||
|         var m = target.Length; | ||||
|  | ||||
|         if (n == 0) | ||||
|         { | ||||
|             return m; | ||||
|         } | ||||
|  | ||||
|         if (m == 0) | ||||
|         { | ||||
|             return n; | ||||
|         } | ||||
|  | ||||
|         var d = new int[n + 1, m + 1]; | ||||
|         Enumerable.Range(0, n + 1).ToList().ForEach(i => d[i, 0] = i); | ||||
|         Enumerable.Range(0, m + 1).ToList().ForEach(i => d[0, i] = i); | ||||
|  | ||||
|         for (var sourceIndex = 1; sourceIndex <= n; sourceIndex++) | ||||
|         { | ||||
|             for (var targetIndex = 1; targetIndex <= m; targetIndex++) | ||||
|             { | ||||
|                 var cost = (target[targetIndex - 1] == source[sourceIndex - 1]) ? 0 : 1; | ||||
|                 d[sourceIndex, targetIndex] = Math.Min( | ||||
|                     Math.Min(d[sourceIndex - 1, targetIndex] + 1, d[sourceIndex, targetIndex - 1] + 1), | ||||
|                     d[sourceIndex - 1, targetIndex - 1] + cost); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return d[n, m]; | ||||
|     } | ||||
| } | ||||
| @@ -1,46 +1,45 @@ | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| internal static class CommandValidator | ||||
| { | ||||
|     internal static class CommandValidator | ||||
|     public static void ValidateRequiredParameters(CommandTree? tree) | ||||
|     { | ||||
|         public static void ValidateRequiredParameters(CommandTree? tree) | ||||
|         var node = tree?.GetRootCommand(); | ||||
|         while (node != null) | ||||
|         { | ||||
|             var node = tree?.GetRootCommand(); | ||||
|             while (node != null) | ||||
|             foreach (var parameter in node.Unmapped) | ||||
|             { | ||||
|                 foreach (var parameter in node.Unmapped) | ||||
|                 if (parameter.Required) | ||||
|                 { | ||||
|                     if (parameter.Required) | ||||
|                     switch (parameter) | ||||
|                     { | ||||
|                         switch (parameter) | ||||
|                         { | ||||
|                             case CommandArgument argument: | ||||
|                                 throw CommandRuntimeException.MissingRequiredArgument(node, argument); | ||||
|                         } | ||||
|                         case CommandArgument argument: | ||||
|                             throw CommandRuntimeException.MissingRequiredArgument(node, argument); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 node = node.Next; | ||||
|             } | ||||
|  | ||||
|             node = node.Next; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|         public static void ValidateParameter(CommandParameter parameter, CommandValueLookup settings, ITypeResolver resolver) | ||||
|     public static void ValidateParameter(CommandParameter parameter, CommandValueLookup settings, ITypeResolver resolver) | ||||
|     { | ||||
|         var assignedValue = settings.GetValue(parameter); | ||||
|         foreach (var validator in parameter.Validators) | ||||
|         { | ||||
|             var assignedValue = settings.GetValue(parameter); | ||||
|             foreach (var validator in parameter.Validators) | ||||
|             var context = new CommandParameterContext(parameter, resolver, assignedValue); | ||||
|             var validationResult = validator.Validate(context); | ||||
|             if (!validationResult.Successful) | ||||
|             { | ||||
|                 var context = new CommandParameterContext(parameter, resolver, assignedValue); | ||||
|                 var validationResult = validator.Validate(context); | ||||
|                 if (!validationResult.Successful) | ||||
|                 { | ||||
|                     // If there is an error message specified in the parameter validator attribute, | ||||
|                     // then use that one, otherwise use the validation result. | ||||
|                     var result = string.IsNullOrWhiteSpace(validator.ErrorMessage) | ||||
|                         ? validationResult | ||||
|                         : ValidationResult.Error(validator.ErrorMessage); | ||||
|                 // If there is an error message specified in the parameter validator attribute, | ||||
|                 // then use that one, otherwise use the validation result. | ||||
|                 var result = string.IsNullOrWhiteSpace(validator.ErrorMessage) | ||||
|                     ? validationResult | ||||
|                     : ValidationResult.Error(validator.ErrorMessage); | ||||
|  | ||||
|                     throw CommandRuntimeException.ValidationFailed(result); | ||||
|                 } | ||||
|                 throw CommandRuntimeException.ValidationFailed(result); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| } | ||||
| @@ -1,272 +1,271 @@ | ||||
| using System; | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.ComponentModel; | ||||
| using System.Diagnostics.CodeAnalysis; | ||||
| using System.Linq; | ||||
| using Spectre.Console.Rendering; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| [Description("Displays diagnostics about CLI configurations")] | ||||
| [SuppressMessage("Performance", "CA1812: Avoid uninstantiated internal classes")] | ||||
| internal sealed class ExplainCommand : Command<ExplainCommand.Settings> | ||||
| { | ||||
|     [Description("Displays diagnostics about CLI configurations")] | ||||
|     [SuppressMessage("Performance", "CA1812: Avoid uninstantiated internal classes")] | ||||
|     internal sealed class ExplainCommand : Command<ExplainCommand.Settings> | ||||
|     private readonly CommandModel _commandModel; | ||||
|     private readonly IAnsiConsole _writer; | ||||
|  | ||||
|     public ExplainCommand(IConfiguration configuration, CommandModel commandModel) | ||||
|     { | ||||
|         private readonly CommandModel _commandModel; | ||||
|         private readonly IAnsiConsole _writer; | ||||
|         _commandModel = commandModel ?? throw new ArgumentNullException(nameof(commandModel)); | ||||
|         _writer = configuration.Settings.Console.GetConsole(); | ||||
|     } | ||||
|  | ||||
|         public ExplainCommand(IConfiguration configuration, CommandModel commandModel) | ||||
|     public sealed class Settings : CommandSettings | ||||
|     { | ||||
|         public Settings(string[]? commands, bool? detailed, bool includeHidden) | ||||
|         { | ||||
|             _commandModel = commandModel ?? throw new ArgumentNullException(nameof(commandModel)); | ||||
|             _writer = configuration.Settings.Console.GetConsole(); | ||||
|             Commands = commands; | ||||
|             Detailed = detailed; | ||||
|             IncludeHidden = includeHidden; | ||||
|         } | ||||
|  | ||||
|         public sealed class Settings : CommandSettings | ||||
|         [CommandArgument(0, "[command]")] | ||||
|         public string[]? Commands { get; } | ||||
|  | ||||
|         [Description("Include detailed information about the commands.")] | ||||
|         [CommandOption("-d|--detailed")] | ||||
|         public bool? Detailed { get; } | ||||
|  | ||||
|         [Description("Include hidden commands and options.")] | ||||
|         [CommandOption("--hidden")] | ||||
|         public bool IncludeHidden { get; } | ||||
|     } | ||||
|  | ||||
|     public override int Execute([NotNull] CommandContext context, [NotNull] Settings settings) | ||||
|     { | ||||
|         var tree = new Tree("CLI Configuration"); | ||||
|         tree.AddNode(ValueMarkup("Application Name", _commandModel.ApplicationName, "no application name")); | ||||
|         tree.AddNode(ValueMarkup("Parsing Mode", _commandModel.ParsingMode.ToString())); | ||||
|  | ||||
|         if (settings.Commands == null || settings.Commands.Length == 0) | ||||
|         { | ||||
|             public Settings(string[]? commands, bool? detailed, bool includeHidden) | ||||
|             { | ||||
|                 Commands = commands; | ||||
|                 Detailed = detailed; | ||||
|                 IncludeHidden = includeHidden; | ||||
|             } | ||||
|             // If there is a default command we'll want to include it in the list too. | ||||
|             var commands = _commandModel.DefaultCommand != null | ||||
|                 ? new[] { _commandModel.DefaultCommand }.Concat(_commandModel.Commands) | ||||
|                 : _commandModel.Commands; | ||||
|  | ||||
|             [CommandArgument(0, "[command]")] | ||||
|             public string[]? Commands { get; } | ||||
|  | ||||
|             [Description("Include detailed information about the commands.")] | ||||
|             [CommandOption("-d|--detailed")] | ||||
|             public bool? Detailed { get; } | ||||
|  | ||||
|             [Description("Include hidden commands and options.")] | ||||
|             [CommandOption("--hidden")] | ||||
|             public bool IncludeHidden { get; } | ||||
|             AddCommands( | ||||
|                 tree.AddNode(ParentMarkup("Commands")), | ||||
|                 commands, | ||||
|                 settings.Detailed ?? false, | ||||
|                 settings.IncludeHidden); | ||||
|         } | ||||
|  | ||||
|         public override int Execute([NotNull] CommandContext context, [NotNull] Settings settings) | ||||
|         else | ||||
|         { | ||||
|             var tree = new Tree("CLI Configuration"); | ||||
|             tree.AddNode(ValueMarkup("Application Name", _commandModel.ApplicationName, "no application name")); | ||||
|             tree.AddNode(ValueMarkup("Parsing Mode", _commandModel.ParsingMode.ToString())); | ||||
|  | ||||
|             if (settings.Commands == null || settings.Commands.Length == 0) | ||||
|             var currentCommandTier = _commandModel.Commands; | ||||
|             CommandInfo? currentCommand = null; | ||||
|             foreach (var command in settings.Commands) | ||||
|             { | ||||
|                 // If there is a default command we'll want to include it in the list too. | ||||
|                 var commands = _commandModel.DefaultCommand != null | ||||
|                     ? new[] { _commandModel.DefaultCommand }.Concat(_commandModel.Commands) | ||||
|                     : _commandModel.Commands; | ||||
|  | ||||
|                 AddCommands( | ||||
|                     tree.AddNode(ParentMarkup("Commands")), | ||||
|                     commands, | ||||
|                     settings.Detailed ?? false, | ||||
|                     settings.IncludeHidden); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 var currentCommandTier = _commandModel.Commands; | ||||
|                 CommandInfo? currentCommand = null; | ||||
|                 foreach (var command in settings.Commands) | ||||
|                 { | ||||
|                     currentCommand = currentCommandTier | ||||
|                         .SingleOrDefault(i => | ||||
|                             i.Name.Equals(command, StringComparison.CurrentCultureIgnoreCase) || | ||||
|                             i.Aliases | ||||
|                             .Any(alias => alias.Equals(command, StringComparison.CurrentCultureIgnoreCase))); | ||||
|  | ||||
|                     if (currentCommand == null) | ||||
|                     { | ||||
|                         break; | ||||
|                     } | ||||
|  | ||||
|                     currentCommandTier = currentCommand.Children; | ||||
|                 } | ||||
|                 currentCommand = currentCommandTier | ||||
|                     .SingleOrDefault(i => | ||||
|                         i.Name.Equals(command, StringComparison.CurrentCultureIgnoreCase) || | ||||
|                         i.Aliases | ||||
|                         .Any(alias => alias.Equals(command, StringComparison.CurrentCultureIgnoreCase))); | ||||
|  | ||||
|                 if (currentCommand == null) | ||||
|                 { | ||||
|                     throw new Exception($"Command {string.Join(" ", settings.Commands)} not found"); | ||||
|                     break; | ||||
|                 } | ||||
|  | ||||
|                 AddCommands( | ||||
|                     tree.AddNode(ParentMarkup("Commands")), | ||||
|                     new[] { currentCommand }, | ||||
|                     settings.Detailed ?? true, | ||||
|                     settings.IncludeHidden); | ||||
|                 currentCommandTier = currentCommand.Children; | ||||
|             } | ||||
|  | ||||
|             _writer.Write(tree); | ||||
|             if (currentCommand == null) | ||||
|             { | ||||
|                 throw new Exception($"Command {string.Join(" ", settings.Commands)} not found"); | ||||
|             } | ||||
|  | ||||
|             return 0; | ||||
|             AddCommands( | ||||
|                 tree.AddNode(ParentMarkup("Commands")), | ||||
|                 new[] { currentCommand }, | ||||
|                 settings.Detailed ?? true, | ||||
|                 settings.IncludeHidden); | ||||
|         } | ||||
|  | ||||
|         private IRenderable ValueMarkup(string key, string value) | ||||
|         _writer.Write(tree); | ||||
|  | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     private IRenderable ValueMarkup(string key, string value) | ||||
|     { | ||||
|         return new Markup($"{key}: [blue]{value.EscapeMarkup()}[/]"); | ||||
|     } | ||||
|  | ||||
|     private IRenderable ValueMarkup(string key, string? value, string noValueText) | ||||
|     { | ||||
|         if (string.IsNullOrWhiteSpace(value)) | ||||
|         { | ||||
|             return new Markup($"{key}: [blue]{value.EscapeMarkup()}[/]"); | ||||
|             return new Markup($"{key}: [grey]({noValueText.EscapeMarkup()})[/]"); | ||||
|         } | ||||
|  | ||||
|         private IRenderable ValueMarkup(string key, string? value, string noValueText) | ||||
|         { | ||||
|             if (string.IsNullOrWhiteSpace(value)) | ||||
|             { | ||||
|                 return new Markup($"{key}: [grey]({noValueText.EscapeMarkup()})[/]"); | ||||
|             } | ||||
|         var table = new Table().NoBorder().HideHeaders().AddColumns("key", "value"); | ||||
|         table.AddRow($"{key}", $"[blue]{value.EscapeMarkup()}[/]"); | ||||
|         return table; | ||||
|     } | ||||
|  | ||||
|             var table = new Table().NoBorder().HideHeaders().AddColumns("key", "value"); | ||||
|             table.AddRow($"{key}", $"[blue]{value.EscapeMarkup()}[/]"); | ||||
|             return table; | ||||
|     private string ParentMarkup(string description) | ||||
|     { | ||||
|         return $"[yellow]{description.EscapeMarkup()}[/]"; | ||||
|     } | ||||
|  | ||||
|     private void AddStringList(TreeNode node, string description, IList<string>? strings) | ||||
|     { | ||||
|         if (strings == null || strings.Count == 0) | ||||
|         { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         private string ParentMarkup(string description) | ||||
|         var parentNode = node.AddNode(ParentMarkup(description)); | ||||
|         foreach (var s in strings) | ||||
|         { | ||||
|             return $"[yellow]{description.EscapeMarkup()}[/]"; | ||||
|         } | ||||
|  | ||||
|         private void AddStringList(TreeNode node, string description, IList<string>? strings) | ||||
|         { | ||||
|             if (strings == null || strings.Count == 0) | ||||
|             { | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             var parentNode = node.AddNode(ParentMarkup(description)); | ||||
|             foreach (var s in strings) | ||||
|             { | ||||
|                 parentNode.AddNode(s); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         private void AddCommands(TreeNode node, IEnumerable<CommandInfo> commands, bool detailed, bool includeHidden) | ||||
|         { | ||||
|             foreach (var command in commands) | ||||
|             { | ||||
|                 if (!includeHidden && command.IsHidden) | ||||
|                 { | ||||
|                     continue; | ||||
|                 } | ||||
|  | ||||
|                 var commandName = $"[green]{command.Name}[/]"; | ||||
|                 if (command.IsDefaultCommand) | ||||
|                 { | ||||
|                     commandName += " (default)"; | ||||
|                 } | ||||
|  | ||||
|                 var commandNode = node.AddNode(commandName); | ||||
|                 commandNode.AddNode(ValueMarkup("Description", command.Description, "no description")); | ||||
|                 if (command.IsHidden) | ||||
|                 { | ||||
|                     commandNode.AddNode(ValueMarkup("IsHidden", command.IsHidden.ToString())); | ||||
|                 } | ||||
|  | ||||
|                 if (!command.IsBranch) | ||||
|                 { | ||||
|                     commandNode.AddNode(ValueMarkup("Type", command.CommandType?.ToString(), "no command type")); | ||||
|                     commandNode.AddNode(ValueMarkup("Settings Type", command.SettingsType.ToString())); | ||||
|                 } | ||||
|  | ||||
|                 if (command.Parameters.Count > 0) | ||||
|                 { | ||||
|                     var parametersNode = commandNode.AddNode(ParentMarkup("Parameters")); | ||||
|                     foreach (var parameter in command.Parameters) | ||||
|                     { | ||||
|                         AddParameter(parametersNode, parameter, detailed, includeHidden); | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 AddStringList(commandNode, "Aliases", command.Aliases.ToList()); | ||||
|                 AddStringList(commandNode, "Examples", command.Examples.Select(i => string.Join(" ", i)).ToList()); | ||||
|  | ||||
|                 if (command.Children.Count > 0) | ||||
|                 { | ||||
|                     var childNode = commandNode.AddNode(ParentMarkup("Child Commands")); | ||||
|                     AddCommands(childNode, command.Children, detailed, includeHidden); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         private void AddParameter(TreeNode parametersNode, CommandParameter parameter, bool detailed, bool includeHidden) | ||||
|         { | ||||
|             if (!includeHidden && parameter.IsHidden) | ||||
|             { | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             if (!detailed) | ||||
|             { | ||||
|                 parametersNode.AddNode( | ||||
|                     $"{parameter.PropertyName} [purple]{GetShortOptions(parameter)}[/] [grey]{parameter.Property.PropertyType.ToString().EscapeMarkup()}[/]"); | ||||
|  | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             var parameterNode = parametersNode.AddNode( | ||||
|                 $"{parameter.PropertyName} [grey]{parameter.Property.PropertyType.ToString().EscapeMarkup()}[/]"); | ||||
|  | ||||
|             parameterNode.AddNode(ValueMarkup("Description", parameter.Description, "no description")); | ||||
|             parameterNode.AddNode(ValueMarkup("Parameter Kind", parameter.ParameterKind.ToString())); | ||||
|  | ||||
|             if (parameter is CommandOption commandOptionParameter) | ||||
|             { | ||||
|                 if (commandOptionParameter.IsShadowed) | ||||
|                 { | ||||
|                     parameterNode.AddNode(ValueMarkup("IsShadowed", commandOptionParameter.IsShadowed.ToString())); | ||||
|                 } | ||||
|  | ||||
|                 if (commandOptionParameter.LongNames.Count > 0) | ||||
|                 { | ||||
|                     parameterNode.AddNode(ValueMarkup( | ||||
|                         "Long Names", | ||||
|                         string.Join("|", commandOptionParameter.LongNames.Select(i => $"--{i}")))); | ||||
|  | ||||
|                     parameterNode.AddNode(ValueMarkup( | ||||
|                         "Short Names", | ||||
|                         string.Join("|", commandOptionParameter.ShortNames.Select(i => $"-{i}")))); | ||||
|                 } | ||||
|             } | ||||
|             else if (parameter is CommandArgument commandArgumentParameter) | ||||
|             { | ||||
|                 parameterNode.AddNode(ValueMarkup("Position", commandArgumentParameter.Position.ToString())); | ||||
|                 parameterNode.AddNode(ValueMarkup("Value", commandArgumentParameter.Value)); | ||||
|             } | ||||
|  | ||||
|             parameterNode.AddNode(ValueMarkup("Required", parameter.Required.ToString())); | ||||
|  | ||||
|             if (parameter.Converter != null) | ||||
|             { | ||||
|                 parameterNode.AddNode(ValueMarkup( | ||||
|                     "Converter", $"\"{parameter.Converter.ConverterTypeName}\"")); | ||||
|             } | ||||
|  | ||||
|             if (parameter.DefaultValue != null) | ||||
|             { | ||||
|                 parameterNode.AddNode(ValueMarkup( | ||||
|                     "Default Value", $"\"{parameter.DefaultValue.Value}\"")); | ||||
|             } | ||||
|  | ||||
|             if (parameter.PairDeconstructor != null) | ||||
|             { | ||||
|                 parameterNode.AddNode(ValueMarkup("Pair Deconstructor", parameter.PairDeconstructor.Type.ToString())); | ||||
|             } | ||||
|  | ||||
|             AddStringList( | ||||
|                 parameterNode, | ||||
|                 "Validators", | ||||
|                 parameter.Validators.Select(i => i.GetType().ToString()).ToList()); | ||||
|         } | ||||
|  | ||||
|         private static string GetShortOptions(CommandParameter parameter) | ||||
|         { | ||||
|             if (parameter is CommandOption commandOptionParameter) | ||||
|             { | ||||
|                 return string.Join( | ||||
|                     " | ", | ||||
|                     commandOptionParameter.LongNames.Select(i => $"--{i}") | ||||
|                         .Concat(commandOptionParameter.ShortNames.Select(i => $"-{i}"))); | ||||
|             } | ||||
|  | ||||
|             if (parameter is CommandArgument commandArgumentParameter) | ||||
|             { | ||||
|                 return $"{commandArgumentParameter.Value} position {commandArgumentParameter.Position}"; | ||||
|             } | ||||
|  | ||||
|             return string.Empty; | ||||
|             parentNode.AddNode(s); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private void AddCommands(TreeNode node, IEnumerable<CommandInfo> commands, bool detailed, bool includeHidden) | ||||
|     { | ||||
|         foreach (var command in commands) | ||||
|         { | ||||
|             if (!includeHidden && command.IsHidden) | ||||
|             { | ||||
|                 continue; | ||||
|             } | ||||
|  | ||||
|             var commandName = $"[green]{command.Name}[/]"; | ||||
|             if (command.IsDefaultCommand) | ||||
|             { | ||||
|                 commandName += " (default)"; | ||||
|             } | ||||
|  | ||||
|             var commandNode = node.AddNode(commandName); | ||||
|             commandNode.AddNode(ValueMarkup("Description", command.Description, "no description")); | ||||
|             if (command.IsHidden) | ||||
|             { | ||||
|                 commandNode.AddNode(ValueMarkup("IsHidden", command.IsHidden.ToString())); | ||||
|             } | ||||
|  | ||||
|             if (!command.IsBranch) | ||||
|             { | ||||
|                 commandNode.AddNode(ValueMarkup("Type", command.CommandType?.ToString(), "no command type")); | ||||
|                 commandNode.AddNode(ValueMarkup("Settings Type", command.SettingsType.ToString())); | ||||
|             } | ||||
|  | ||||
|             if (command.Parameters.Count > 0) | ||||
|             { | ||||
|                 var parametersNode = commandNode.AddNode(ParentMarkup("Parameters")); | ||||
|                 foreach (var parameter in command.Parameters) | ||||
|                 { | ||||
|                     AddParameter(parametersNode, parameter, detailed, includeHidden); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             AddStringList(commandNode, "Aliases", command.Aliases.ToList()); | ||||
|             AddStringList(commandNode, "Examples", command.Examples.Select(i => string.Join(" ", i)).ToList()); | ||||
|  | ||||
|             if (command.Children.Count > 0) | ||||
|             { | ||||
|                 var childNode = commandNode.AddNode(ParentMarkup("Child Commands")); | ||||
|                 AddCommands(childNode, command.Children, detailed, includeHidden); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private void AddParameter(TreeNode parametersNode, CommandParameter parameter, bool detailed, bool includeHidden) | ||||
|     { | ||||
|         if (!includeHidden && parameter.IsHidden) | ||||
|         { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         if (!detailed) | ||||
|         { | ||||
|             parametersNode.AddNode( | ||||
|                 $"{parameter.PropertyName} [purple]{GetShortOptions(parameter)}[/] [grey]{parameter.Property.PropertyType.ToString().EscapeMarkup()}[/]"); | ||||
|  | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         var parameterNode = parametersNode.AddNode( | ||||
|             $"{parameter.PropertyName} [grey]{parameter.Property.PropertyType.ToString().EscapeMarkup()}[/]"); | ||||
|  | ||||
|         parameterNode.AddNode(ValueMarkup("Description", parameter.Description, "no description")); | ||||
|         parameterNode.AddNode(ValueMarkup("Parameter Kind", parameter.ParameterKind.ToString())); | ||||
|  | ||||
|         if (parameter is CommandOption commandOptionParameter) | ||||
|         { | ||||
|             if (commandOptionParameter.IsShadowed) | ||||
|             { | ||||
|                 parameterNode.AddNode(ValueMarkup("IsShadowed", commandOptionParameter.IsShadowed.ToString())); | ||||
|             } | ||||
|  | ||||
|             if (commandOptionParameter.LongNames.Count > 0) | ||||
|             { | ||||
|                 parameterNode.AddNode(ValueMarkup( | ||||
|                     "Long Names", | ||||
|                     string.Join("|", commandOptionParameter.LongNames.Select(i => $"--{i}")))); | ||||
|  | ||||
|                 parameterNode.AddNode(ValueMarkup( | ||||
|                     "Short Names", | ||||
|                     string.Join("|", commandOptionParameter.ShortNames.Select(i => $"-{i}")))); | ||||
|             } | ||||
|         } | ||||
|         else if (parameter is CommandArgument commandArgumentParameter) | ||||
|         { | ||||
|             parameterNode.AddNode(ValueMarkup("Position", commandArgumentParameter.Position.ToString())); | ||||
|             parameterNode.AddNode(ValueMarkup("Value", commandArgumentParameter.Value)); | ||||
|         } | ||||
|  | ||||
|         parameterNode.AddNode(ValueMarkup("Required", parameter.Required.ToString())); | ||||
|  | ||||
|         if (parameter.Converter != null) | ||||
|         { | ||||
|             parameterNode.AddNode(ValueMarkup( | ||||
|                 "Converter", $"\"{parameter.Converter.ConverterTypeName}\"")); | ||||
|         } | ||||
|  | ||||
|         if (parameter.DefaultValue != null) | ||||
|         { | ||||
|             parameterNode.AddNode(ValueMarkup( | ||||
|                 "Default Value", $"\"{parameter.DefaultValue.Value}\"")); | ||||
|         } | ||||
|  | ||||
|         if (parameter.PairDeconstructor != null) | ||||
|         { | ||||
|             parameterNode.AddNode(ValueMarkup("Pair Deconstructor", parameter.PairDeconstructor.Type.ToString())); | ||||
|         } | ||||
|  | ||||
|         AddStringList( | ||||
|             parameterNode, | ||||
|             "Validators", | ||||
|             parameter.Validators.Select(i => i.GetType().ToString()).ToList()); | ||||
|     } | ||||
|  | ||||
|     private static string GetShortOptions(CommandParameter parameter) | ||||
|     { | ||||
|         if (parameter is CommandOption commandOptionParameter) | ||||
|         { | ||||
|             return string.Join( | ||||
|                 " | ", | ||||
|                 commandOptionParameter.LongNames.Select(i => $"--{i}") | ||||
|                     .Concat(commandOptionParameter.ShortNames.Select(i => $"-{i}"))); | ||||
|         } | ||||
|  | ||||
|         if (parameter is CommandArgument commandArgumentParameter) | ||||
|         { | ||||
|             return $"{commandArgumentParameter.Value} position {commandArgumentParameter.Position}"; | ||||
|         } | ||||
|  | ||||
|         return string.Empty; | ||||
|     } | ||||
| } | ||||
| @@ -1,34 +1,33 @@ | ||||
| using System.ComponentModel; | ||||
| using System.Diagnostics.CodeAnalysis; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| [Description("Displays the CLI library version")] | ||||
| [SuppressMessage("Performance", "CA1812: Avoid uninstantiated internal classes")] | ||||
| internal sealed class VersionCommand : Command<VersionCommand.Settings> | ||||
| { | ||||
|     [Description("Displays the CLI library version")] | ||||
|     [SuppressMessage("Performance", "CA1812: Avoid uninstantiated internal classes")] | ||||
|     internal sealed class VersionCommand : Command<VersionCommand.Settings> | ||||
|     private readonly IAnsiConsole _writer; | ||||
|  | ||||
|     public VersionCommand(IConfiguration configuration) | ||||
|     { | ||||
|         private readonly IAnsiConsole _writer; | ||||
|  | ||||
|         public VersionCommand(IConfiguration configuration) | ||||
|         { | ||||
|             _writer = configuration.Settings.Console.GetConsole(); | ||||
|         } | ||||
|  | ||||
|         public sealed class Settings : CommandSettings | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         public override int Execute([NotNull] CommandContext context, [NotNull] Settings settings) | ||||
|         { | ||||
|             _writer.MarkupLine( | ||||
|                 "[yellow]Spectre.Cli[/] version [aqua]{0}[/]", | ||||
|                 VersionHelper.GetVersion(typeof(VersionCommand)?.Assembly)); | ||||
|  | ||||
|             _writer.MarkupLine( | ||||
|                 "[yellow]Spectre.Console[/] version [aqua]{0}[/]", | ||||
|                 VersionHelper.GetVersion(typeof(IAnsiConsole)?.Assembly)); | ||||
|  | ||||
|             return 0; | ||||
|         } | ||||
|         _writer = configuration.Settings.Console.GetConsole(); | ||||
|     } | ||||
| } | ||||
|  | ||||
|     public sealed class Settings : CommandSettings | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     public override int Execute([NotNull] CommandContext context, [NotNull] Settings settings) | ||||
|     { | ||||
|         _writer.MarkupLine( | ||||
|             "[yellow]Spectre.Cli[/] version [aqua]{0}[/]", | ||||
|             VersionHelper.GetVersion(typeof(VersionCommand)?.Assembly)); | ||||
|  | ||||
|         _writer.MarkupLine( | ||||
|             "[yellow]Spectre.Console[/] version [aqua]{0}[/]", | ||||
|             VersionHelper.GetVersion(typeof(IAnsiConsole)?.Assembly)); | ||||
|  | ||||
|         return 0; | ||||
|     } | ||||
| } | ||||
| @@ -7,179 +7,178 @@ using System.Linq; | ||||
| using System.Text; | ||||
| using System.Xml; | ||||
|  | ||||
| namespace Spectre.Console.Cli | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| [Description("Generates an XML representation of the CLI configuration.")] | ||||
| [SuppressMessage("Performance", "CA1812: Avoid uninstantiated internal classes")] | ||||
| internal sealed class XmlDocCommand : Command<XmlDocCommand.Settings> | ||||
| { | ||||
|     [Description("Generates an XML representation of the CLI configuration.")] | ||||
|     [SuppressMessage("Performance", "CA1812: Avoid uninstantiated internal classes")] | ||||
|     internal sealed class XmlDocCommand : Command<XmlDocCommand.Settings> | ||||
|     private readonly CommandModel _model; | ||||
|     private readonly IAnsiConsole _writer; | ||||
|  | ||||
|     public XmlDocCommand(IConfiguration configuration, CommandModel model) | ||||
|     { | ||||
|         private readonly CommandModel _model; | ||||
|         private readonly IAnsiConsole _writer; | ||||
|         _model = model ?? throw new ArgumentNullException(nameof(model)); | ||||
|         _writer = configuration.Settings.Console.GetConsole(); | ||||
|     } | ||||
|  | ||||
|         public XmlDocCommand(IConfiguration configuration, CommandModel model) | ||||
|     public sealed class Settings : CommandSettings | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     public override int Execute([NotNull] CommandContext context, [NotNull] Settings settings) | ||||
|     { | ||||
|         _writer.Write(Serialize(_model), Style.Plain); | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     public static string Serialize(CommandModel model) | ||||
|     { | ||||
|         var settings = new XmlWriterSettings | ||||
|         { | ||||
|             _model = model ?? throw new ArgumentNullException(nameof(model)); | ||||
|             _writer = configuration.Settings.Console.GetConsole(); | ||||
|         } | ||||
|             Indent = true, | ||||
|             IndentChars = "  ", | ||||
|             NewLineChars = "\n", | ||||
|             OmitXmlDeclaration = false, | ||||
|             Encoding = Encoding.UTF8, | ||||
|         }; | ||||
|  | ||||
|         public sealed class Settings : CommandSettings | ||||
|         using (var buffer = new StringWriterWithEncoding(Encoding.UTF8)) | ||||
|         using (var xmlWriter = XmlWriter.Create(buffer, settings)) | ||||
|         { | ||||
|         } | ||||
|  | ||||
|         public override int Execute([NotNull] CommandContext context, [NotNull] Settings settings) | ||||
|         { | ||||
|             _writer.Write(Serialize(_model), Style.Plain); | ||||
|             return 0; | ||||
|         } | ||||
|  | ||||
|         public static string Serialize(CommandModel model) | ||||
|         { | ||||
|             var settings = new XmlWriterSettings | ||||
|             { | ||||
|                 Indent = true, | ||||
|                 IndentChars = "  ", | ||||
|                 NewLineChars = "\n", | ||||
|                 OmitXmlDeclaration = false, | ||||
|                 Encoding = Encoding.UTF8, | ||||
|             }; | ||||
|  | ||||
|             using (var buffer = new StringWriterWithEncoding(Encoding.UTF8)) | ||||
|             using (var xmlWriter = XmlWriter.Create(buffer, settings)) | ||||
|             { | ||||
|                 SerializeModel(model).WriteTo(xmlWriter); | ||||
|                 xmlWriter.Flush(); | ||||
|                 return buffer.GetStringBuilder().ToString(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         private static XmlDocument SerializeModel(CommandModel model) | ||||
|         { | ||||
|             var document = new XmlDocument(); | ||||
|             var root = document.CreateElement("Model"); | ||||
|  | ||||
|             if (model.DefaultCommand != null) | ||||
|             { | ||||
|                 root.AppendChild(document.CreateComment("DEFAULT COMMAND")); | ||||
|                 root.AppendChild(CreateCommandNode(document, model.DefaultCommand, isDefaultCommand: true)); | ||||
|             } | ||||
|  | ||||
|             foreach (var command in model.Commands.Where(x => !x.IsHidden)) | ||||
|             { | ||||
|                 root.AppendChild(document.CreateComment(command.Name.ToUpperInvariant())); | ||||
|                 root.AppendChild(CreateCommandNode(document, command)); | ||||
|             } | ||||
|  | ||||
|             document.AppendChild(root); | ||||
|             return document; | ||||
|         } | ||||
|  | ||||
|         private static XmlNode CreateCommandNode(XmlDocument doc, CommandInfo command, bool isDefaultCommand = false) | ||||
|         { | ||||
|             var node = doc.CreateElement("Command"); | ||||
|  | ||||
|             // Attributes | ||||
|             node.SetNullableAttribute("Name", command.Name); | ||||
|             node.SetBooleanAttribute("IsBranch", command.IsBranch); | ||||
|  | ||||
|             if (isDefaultCommand) | ||||
|             { | ||||
|                 node.SetBooleanAttribute("IsDefault", true); | ||||
|             } | ||||
|  | ||||
|             if (command.CommandType != null) | ||||
|             { | ||||
|                 node.SetNullableAttribute("ClrType", command.CommandType?.FullName); | ||||
|             } | ||||
|  | ||||
|             node.SetNullableAttribute("Settings", command.SettingsType?.FullName); | ||||
|  | ||||
|             // Parameters | ||||
|             if (command.Parameters.Count > 0) | ||||
|             { | ||||
|                 var parameterRootNode = doc.CreateElement("Parameters"); | ||||
|                 foreach (var parameter in CreateParameterNodes(doc, command)) | ||||
|                 { | ||||
|                     parameterRootNode.AppendChild(parameter); | ||||
|                 } | ||||
|  | ||||
|                 node.AppendChild(parameterRootNode); | ||||
|             } | ||||
|  | ||||
|             // Commands | ||||
|             foreach (var childCommand in command.Children) | ||||
|             { | ||||
|                 node.AppendChild(doc.CreateComment(childCommand.Name.ToUpperInvariant())); | ||||
|                 node.AppendChild(CreateCommandNode(doc, childCommand)); | ||||
|             } | ||||
|  | ||||
|             return node; | ||||
|         } | ||||
|  | ||||
|         private static IEnumerable<XmlNode> CreateParameterNodes(XmlDocument document, CommandInfo command) | ||||
|         { | ||||
|             // Arguments | ||||
|             foreach (var argument in command.Parameters.OfType<CommandArgument>().OrderBy(x => x.Position)) | ||||
|             { | ||||
|                 var node = document.CreateElement("Argument"); | ||||
|                 node.SetNullableAttribute("Name", argument.Value); | ||||
|                 node.SetAttribute("Position", argument.Position.ToString(CultureInfo.InvariantCulture)); | ||||
|                 node.SetBooleanAttribute("Required", argument.Required); | ||||
|                 node.SetEnumAttribute("Kind", argument.ParameterKind); | ||||
|                 node.SetNullableAttribute("ClrType", argument.ParameterType?.FullName); | ||||
|  | ||||
|                 if (!string.IsNullOrWhiteSpace(argument.Description)) | ||||
|                 { | ||||
|                     var descriptionNode = document.CreateElement("Description"); | ||||
|                     descriptionNode.InnerText = argument.Description; | ||||
|                     node.AppendChild(descriptionNode); | ||||
|                 } | ||||
|  | ||||
|                 if (argument.Validators.Count > 0) | ||||
|                 { | ||||
|                     var validatorRootNode = document.CreateElement("Validators"); | ||||
|                     foreach (var validator in argument.Validators.OrderBy(x => x.GetType().FullName)) | ||||
|                     { | ||||
|                         var validatorNode = document.CreateElement("Validator"); | ||||
|                         validatorNode.SetNullableAttribute("ClrType", validator.GetType().FullName); | ||||
|                         validatorNode.SetNullableAttribute("Message", validator.ErrorMessage); | ||||
|                         validatorRootNode.AppendChild(validatorNode); | ||||
|                     } | ||||
|  | ||||
|                     node.AppendChild(validatorRootNode); | ||||
|                 } | ||||
|  | ||||
|                 yield return node; | ||||
|             } | ||||
|  | ||||
|             // Options | ||||
|             foreach (var option in command.Parameters.OfType<CommandOption>() | ||||
|                 .Where(x => !x.IsHidden) | ||||
|                 .OrderBy(x => string.Join(",", x.LongNames)) | ||||
|                 .ThenBy(x => string.Join(",", x.ShortNames))) | ||||
|             { | ||||
|                 var node = document.CreateElement("Option"); | ||||
|  | ||||
|                 if (option.IsShadowed) | ||||
|                 { | ||||
|                     node.SetBooleanAttribute("Shadowed", true); | ||||
|                 } | ||||
|  | ||||
|                 node.SetNullableAttribute("Short", option.ShortNames); | ||||
|                 node.SetNullableAttribute("Long", option.LongNames); | ||||
|                 node.SetNullableAttribute("Value", option.ValueName); | ||||
|                 node.SetBooleanAttribute("Required", option.Required); | ||||
|                 node.SetEnumAttribute("Kind", option.ParameterKind); | ||||
|                 node.SetNullableAttribute("ClrType", option.ParameterType?.FullName); | ||||
|  | ||||
|                 if (!string.IsNullOrWhiteSpace(option.Description)) | ||||
|                 { | ||||
|                     var descriptionNode = document.CreateElement("Description"); | ||||
|                     descriptionNode.InnerText = option.Description; | ||||
|                     node.AppendChild(descriptionNode); | ||||
|                 } | ||||
|  | ||||
|                 yield return node; | ||||
|             } | ||||
|             SerializeModel(model).WriteTo(xmlWriter); | ||||
|             xmlWriter.Flush(); | ||||
|             return buffer.GetStringBuilder().ToString(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
|     private static XmlDocument SerializeModel(CommandModel model) | ||||
|     { | ||||
|         var document = new XmlDocument(); | ||||
|         var root = document.CreateElement("Model"); | ||||
|  | ||||
|         if (model.DefaultCommand != null) | ||||
|         { | ||||
|             root.AppendChild(document.CreateComment("DEFAULT COMMAND")); | ||||
|             root.AppendChild(CreateCommandNode(document, model.DefaultCommand, isDefaultCommand: true)); | ||||
|         } | ||||
|  | ||||
|         foreach (var command in model.Commands.Where(x => !x.IsHidden)) | ||||
|         { | ||||
|             root.AppendChild(document.CreateComment(command.Name.ToUpperInvariant())); | ||||
|             root.AppendChild(CreateCommandNode(document, command)); | ||||
|         } | ||||
|  | ||||
|         document.AppendChild(root); | ||||
|         return document; | ||||
|     } | ||||
|  | ||||
|     private static XmlNode CreateCommandNode(XmlDocument doc, CommandInfo command, bool isDefaultCommand = false) | ||||
|     { | ||||
|         var node = doc.CreateElement("Command"); | ||||
|  | ||||
|         // Attributes | ||||
|         node.SetNullableAttribute("Name", command.Name); | ||||
|         node.SetBooleanAttribute("IsBranch", command.IsBranch); | ||||
|  | ||||
|         if (isDefaultCommand) | ||||
|         { | ||||
|             node.SetBooleanAttribute("IsDefault", true); | ||||
|         } | ||||
|  | ||||
|         if (command.CommandType != null) | ||||
|         { | ||||
|             node.SetNullableAttribute("ClrType", command.CommandType?.FullName); | ||||
|         } | ||||
|  | ||||
|         node.SetNullableAttribute("Settings", command.SettingsType?.FullName); | ||||
|  | ||||
|         // Parameters | ||||
|         if (command.Parameters.Count > 0) | ||||
|         { | ||||
|             var parameterRootNode = doc.CreateElement("Parameters"); | ||||
|             foreach (var parameter in CreateParameterNodes(doc, command)) | ||||
|             { | ||||
|                 parameterRootNode.AppendChild(parameter); | ||||
|             } | ||||
|  | ||||
|             node.AppendChild(parameterRootNode); | ||||
|         } | ||||
|  | ||||
|         // Commands | ||||
|         foreach (var childCommand in command.Children) | ||||
|         { | ||||
|             node.AppendChild(doc.CreateComment(childCommand.Name.ToUpperInvariant())); | ||||
|             node.AppendChild(CreateCommandNode(doc, childCommand)); | ||||
|         } | ||||
|  | ||||
|         return node; | ||||
|     } | ||||
|  | ||||
|     private static IEnumerable<XmlNode> CreateParameterNodes(XmlDocument document, CommandInfo command) | ||||
|     { | ||||
|         // Arguments | ||||
|         foreach (var argument in command.Parameters.OfType<CommandArgument>().OrderBy(x => x.Position)) | ||||
|         { | ||||
|             var node = document.CreateElement("Argument"); | ||||
|             node.SetNullableAttribute("Name", argument.Value); | ||||
|             node.SetAttribute("Position", argument.Position.ToString(CultureInfo.InvariantCulture)); | ||||
|             node.SetBooleanAttribute("Required", argument.Required); | ||||
|             node.SetEnumAttribute("Kind", argument.ParameterKind); | ||||
|             node.SetNullableAttribute("ClrType", argument.ParameterType?.FullName); | ||||
|  | ||||
|             if (!string.IsNullOrWhiteSpace(argument.Description)) | ||||
|             { | ||||
|                 var descriptionNode = document.CreateElement("Description"); | ||||
|                 descriptionNode.InnerText = argument.Description; | ||||
|                 node.AppendChild(descriptionNode); | ||||
|             } | ||||
|  | ||||
|             if (argument.Validators.Count > 0) | ||||
|             { | ||||
|                 var validatorRootNode = document.CreateElement("Validators"); | ||||
|                 foreach (var validator in argument.Validators.OrderBy(x => x.GetType().FullName)) | ||||
|                 { | ||||
|                     var validatorNode = document.CreateElement("Validator"); | ||||
|                     validatorNode.SetNullableAttribute("ClrType", validator.GetType().FullName); | ||||
|                     validatorNode.SetNullableAttribute("Message", validator.ErrorMessage); | ||||
|                     validatorRootNode.AppendChild(validatorNode); | ||||
|                 } | ||||
|  | ||||
|                 node.AppendChild(validatorRootNode); | ||||
|             } | ||||
|  | ||||
|             yield return node; | ||||
|         } | ||||
|  | ||||
|         // Options | ||||
|         foreach (var option in command.Parameters.OfType<CommandOption>() | ||||
|             .Where(x => !x.IsHidden) | ||||
|             .OrderBy(x => string.Join(",", x.LongNames)) | ||||
|             .ThenBy(x => string.Join(",", x.ShortNames))) | ||||
|         { | ||||
|             var node = document.CreateElement("Option"); | ||||
|  | ||||
|             if (option.IsShadowed) | ||||
|             { | ||||
|                 node.SetBooleanAttribute("Shadowed", true); | ||||
|             } | ||||
|  | ||||
|             node.SetNullableAttribute("Short", option.ShortNames); | ||||
|             node.SetNullableAttribute("Long", option.LongNames); | ||||
|             node.SetNullableAttribute("Value", option.ValueName); | ||||
|             node.SetBooleanAttribute("Required", option.Required); | ||||
|             node.SetEnumAttribute("Kind", option.ParameterKind); | ||||
|             node.SetNullableAttribute("ClrType", option.ParameterType?.FullName); | ||||
|  | ||||
|             if (!string.IsNullOrWhiteSpace(option.Description)) | ||||
|             { | ||||
|                 var descriptionNode = document.CreateElement("Description"); | ||||
|                 descriptionNode.InnerText = option.Description; | ||||
|                 node.AppendChild(descriptionNode); | ||||
|             } | ||||
|  | ||||
|             yield return node; | ||||
|         } | ||||
|     } | ||||
| } | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user