mirror of
				https://github.com/nsnail/spectre.console.git
				synced 2025-11-01 01:25:27 +08:00 
			
		
		
		
	Expose raw arguments on the command context
This commit is contained in:
		 Patrik Svensson
					Patrik Svensson
				
			
				
					committed by
					
						 Patrik Svensson
						Patrik Svensson
					
				
			
			
				
	
			
			
			 Patrik Svensson
						Patrik Svensson
					
				
			
						parent
						
							de04619f88
						
					
				
				
					commit
					95bff47b85
				
			| @@ -13,6 +13,11 @@ public sealed class CommandContext | ||||
|     /// </value> | ||||
|     public IRemainingArguments Remaining { get; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Gets all the arguments that were passed to the applicaton. | ||||
|     /// </summary> | ||||
|     public IReadOnlyList<string> Arguments { get; } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Gets the name of the command. | ||||
|     /// </summary> | ||||
| @@ -32,11 +37,17 @@ public sealed class CommandContext | ||||
|     /// <summary> | ||||
|     /// Initializes a new instance of the <see cref="CommandContext"/> class. | ||||
|     /// </summary> | ||||
|     /// <param name="arguments">All arguments that were passed to the application.</param> | ||||
|     /// <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) | ||||
|     public CommandContext( | ||||
|         IEnumerable<string> arguments, | ||||
|         IRemainingArguments remaining, | ||||
|         string name, | ||||
|         object? data) | ||||
|     { | ||||
|         Arguments = arguments.ToSafeReadOnlyList(); | ||||
|         Remaining = remaining ?? throw new System.ArgumentNullException(nameof(remaining)); | ||||
|         Name = name ?? throw new System.ArgumentNullException(nameof(name)); | ||||
|         Data = data; | ||||
|   | ||||
| @@ -12,6 +12,7 @@ public interface IRemainingArguments | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Gets the raw, non-parsed remaining arguments. | ||||
|     /// This is normally everything after the `--` delimiter. | ||||
|     /// </summary> | ||||
|     IReadOnlyList<string> Raw { get; } | ||||
| } | ||||
| @@ -17,7 +17,7 @@ internal sealed class CommandExecutor | ||||
|             throw new ArgumentNullException(nameof(configuration)); | ||||
|         } | ||||
|  | ||||
|         args ??= new List<string>(); | ||||
|         var arguments = args.ToSafeReadOnlyList(); | ||||
|  | ||||
|         _registrar.RegisterInstance(typeof(IConfiguration), configuration); | ||||
|         _registrar.RegisterLazy(typeof(IAnsiConsole), () => configuration.Settings.Console.GetConsole()); | ||||
| @@ -31,7 +31,7 @@ internal sealed class CommandExecutor | ||||
|         if (model.DefaultCommand == null) | ||||
|         { | ||||
|             // Got at least one argument? | ||||
|             var firstArgument = args.FirstOrDefault(); | ||||
|             var firstArgument = arguments.FirstOrDefault(); | ||||
|             if (firstArgument != null) | ||||
|             { | ||||
|                 // Asking for version? Kind of a hack, but it's alright. | ||||
| @@ -47,7 +47,7 @@ internal sealed class CommandExecutor | ||||
|         } | ||||
|  | ||||
|         // Parse and map the model against the arguments. | ||||
|         var parsedResult = ParseCommandLineArguments(model, configuration.Settings, args); | ||||
|         var parsedResult = ParseCommandLineArguments(model, configuration.Settings, arguments); | ||||
|  | ||||
|         // Register the arguments with the container. | ||||
|         _registrar.RegisterInstance(typeof(CommandTreeParserResult), parsedResult); | ||||
| @@ -79,7 +79,7 @@ internal sealed class CommandExecutor | ||||
|             } | ||||
|  | ||||
|             // Is this the default and is it called without arguments when there are required arguments? | ||||
|             if (leaf.Command.IsDefaultCommand && args.Count() == 0 && leaf.Command.Parameters.Any(p => p.Required)) | ||||
|             if (leaf.Command.IsDefaultCommand && arguments.Count == 0 && leaf.Command.Parameters.Any(p => p.Required)) | ||||
|             { | ||||
|                 // Display help for default command. | ||||
|                 configuration.Settings.Console.SafeRender(helpProvider.Write(model, leaf.Command)); | ||||
| @@ -87,15 +87,18 @@ internal sealed class CommandExecutor | ||||
|             } | ||||
|  | ||||
|             // Create the content. | ||||
|             var context = new CommandContext(parsedResult.Remaining, leaf.Command.Name, leaf.Command.Data); | ||||
|             var context = new CommandContext( | ||||
|                 arguments, | ||||
|                 parsedResult.Remaining, | ||||
|                 leaf.Command.Name, | ||||
|                 leaf.Command.Data); | ||||
|  | ||||
|             // Execute the command tree. | ||||
|             return await Execute(leaf, parsedResult.Tree, context, resolver, configuration).ConfigureAwait(false); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| #pragma warning disable CS8603 // Possible null reference return. | ||||
|     private CommandTreeParserResult ParseCommandLineArguments(CommandModel model, CommandAppSettings settings, IEnumerable<string> args) | ||||
|     private CommandTreeParserResult ParseCommandLineArguments(CommandModel model, CommandAppSettings settings, IReadOnlyList<string> args) | ||||
|     { | ||||
|         var parser = new CommandTreeParser(model, settings.CaseSensitivity, settings.ParsingMode, settings.ConvertFlagsToRemainingArguments); | ||||
|  | ||||
| @@ -103,7 +106,7 @@ internal sealed class CommandExecutor | ||||
|         var tokenizerResult = CommandTreeTokenizer.Tokenize(args); | ||||
|         var parsedResult = parser.Parse(parserContext, tokenizerResult); | ||||
|  | ||||
|         var lastParsedLeaf = parsedResult?.Tree?.GetLeafCommand(); | ||||
|         var lastParsedLeaf = parsedResult.Tree?.GetLeafCommand(); | ||||
|         var lastParsedCommand = lastParsedLeaf?.Command; | ||||
|         if (lastParsedLeaf != null && lastParsedCommand != null && | ||||
|             lastParsedCommand.IsBranch && !lastParsedLeaf.ShowHelp && | ||||
| @@ -122,7 +125,6 @@ internal sealed class CommandExecutor | ||||
|  | ||||
|         return parsedResult; | ||||
|     } | ||||
| #pragma warning restore CS8603 // Possible null reference return. | ||||
|  | ||||
|     private static string ResolveApplicationVersion(IConfiguration configuration) | ||||
|     { | ||||
|   | ||||
| @@ -0,0 +1,14 @@ | ||||
| namespace Spectre.Console.Cli; | ||||
|  | ||||
| internal static class EnumerableExtensions | ||||
| { | ||||
|     public static IReadOnlyList<T> ToSafeReadOnlyList<T>(this IEnumerable<T> source) | ||||
|     { | ||||
|         return source switch | ||||
|         { | ||||
|             null => new List<T>(), | ||||
|             IReadOnlyList<T> list => list, | ||||
|             _ => source.ToList(), | ||||
|         }; | ||||
|     } | ||||
| } | ||||
| @@ -13,7 +13,7 @@ | ||||
|   </ItemGroup> | ||||
|  | ||||
|   <ItemGroup> | ||||
|     <PackageReference Include="SixLabors.ImageSharp" Version="3.1.3" /> | ||||
|     <PackageReference Include="SixLabors.ImageSharp" Version="3.1.4" /> | ||||
|   </ItemGroup> | ||||
|  | ||||
|   <ItemGroup> | ||||
|   | ||||
| @@ -0,0 +1,23 @@ | ||||
| namespace Spectre.Console.Tests.Unit.Cli; | ||||
|  | ||||
| public sealed partial class CommandAppTests | ||||
| { | ||||
|     [Fact] | ||||
|     [Expectation("Should_Expose_Raw_Arguments")] | ||||
|     public void Should_Return_Correct_Text_When_Command_Is_Unknown() | ||||
|     { | ||||
|         // Given | ||||
|         var app = new CommandAppTester(); | ||||
|         app.Configure(config => | ||||
|         { | ||||
|             config.AddCommand<EmptyCommand>("test"); | ||||
|         }); | ||||
|  | ||||
|         // When | ||||
|         var result = app.Run("test", "--foo", "32", "--lol"); | ||||
|  | ||||
|         // Then | ||||
|         result.Context.ShouldNotBeNull(); | ||||
|         result.Context.Arguments.ShouldBe(new[] { "test", "--foo", "32", "--lol" }); | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user