mirror of
https://github.com/nsnail/spectre.console.git
synced 2025-04-16 08:52:50 +08:00
Expose raw arguments on the command context
This commit is contained in:
parent
de04619f88
commit
95bff47b85
@ -13,6 +13,11 @@ public sealed class CommandContext
|
|||||||
/// </value>
|
/// </value>
|
||||||
public IRemainingArguments Remaining { get; }
|
public IRemainingArguments Remaining { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets all the arguments that were passed to the applicaton.
|
||||||
|
/// </summary>
|
||||||
|
public IReadOnlyList<string> Arguments { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the name of the command.
|
/// Gets the name of the command.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -32,11 +37,17 @@ public sealed class CommandContext
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="CommandContext"/> class.
|
/// Initializes a new instance of the <see cref="CommandContext"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="arguments">All arguments that were passed to the application.</param>
|
||||||
/// <param name="remaining">The remaining arguments.</param>
|
/// <param name="remaining">The remaining arguments.</param>
|
||||||
/// <param name="name">The command name.</param>
|
/// <param name="name">The command name.</param>
|
||||||
/// <param name="data">The command data.</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));
|
Remaining = remaining ?? throw new System.ArgumentNullException(nameof(remaining));
|
||||||
Name = name ?? throw new System.ArgumentNullException(nameof(name));
|
Name = name ?? throw new System.ArgumentNullException(nameof(name));
|
||||||
Data = data;
|
Data = data;
|
||||||
|
@ -12,6 +12,7 @@ public interface IRemainingArguments
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the raw, non-parsed remaining arguments.
|
/// Gets the raw, non-parsed remaining arguments.
|
||||||
|
/// This is normally everything after the `--` delimiter.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IReadOnlyList<string> Raw { get; }
|
IReadOnlyList<string> Raw { get; }
|
||||||
}
|
}
|
@ -17,7 +17,7 @@ internal sealed class CommandExecutor
|
|||||||
throw new ArgumentNullException(nameof(configuration));
|
throw new ArgumentNullException(nameof(configuration));
|
||||||
}
|
}
|
||||||
|
|
||||||
args ??= new List<string>();
|
var arguments = args.ToSafeReadOnlyList();
|
||||||
|
|
||||||
_registrar.RegisterInstance(typeof(IConfiguration), configuration);
|
_registrar.RegisterInstance(typeof(IConfiguration), configuration);
|
||||||
_registrar.RegisterLazy(typeof(IAnsiConsole), () => configuration.Settings.Console.GetConsole());
|
_registrar.RegisterLazy(typeof(IAnsiConsole), () => configuration.Settings.Console.GetConsole());
|
||||||
@ -31,7 +31,7 @@ internal sealed class CommandExecutor
|
|||||||
if (model.DefaultCommand == null)
|
if (model.DefaultCommand == null)
|
||||||
{
|
{
|
||||||
// Got at least one argument?
|
// Got at least one argument?
|
||||||
var firstArgument = args.FirstOrDefault();
|
var firstArgument = arguments.FirstOrDefault();
|
||||||
if (firstArgument != null)
|
if (firstArgument != null)
|
||||||
{
|
{
|
||||||
// Asking for version? Kind of a hack, but it's alright.
|
// 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.
|
// 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.
|
// Register the arguments with the container.
|
||||||
_registrar.RegisterInstance(typeof(CommandTreeParserResult), parsedResult);
|
_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?
|
// 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.
|
// Display help for default command.
|
||||||
configuration.Settings.Console.SafeRender(helpProvider.Write(model, leaf.Command));
|
configuration.Settings.Console.SafeRender(helpProvider.Write(model, leaf.Command));
|
||||||
@ -87,15 +87,18 @@ internal sealed class CommandExecutor
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create the content.
|
// 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.
|
// Execute the command tree.
|
||||||
return await Execute(leaf, parsedResult.Tree, context, resolver, configuration).ConfigureAwait(false);
|
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, IReadOnlyList<string> args)
|
||||||
private CommandTreeParserResult ParseCommandLineArguments(CommandModel model, CommandAppSettings settings, IEnumerable<string> args)
|
|
||||||
{
|
{
|
||||||
var parser = new CommandTreeParser(model, settings.CaseSensitivity, settings.ParsingMode, settings.ConvertFlagsToRemainingArguments);
|
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 tokenizerResult = CommandTreeTokenizer.Tokenize(args);
|
||||||
var parsedResult = parser.Parse(parserContext, tokenizerResult);
|
var parsedResult = parser.Parse(parserContext, tokenizerResult);
|
||||||
|
|
||||||
var lastParsedLeaf = parsedResult?.Tree?.GetLeafCommand();
|
var lastParsedLeaf = parsedResult.Tree?.GetLeafCommand();
|
||||||
var lastParsedCommand = lastParsedLeaf?.Command;
|
var lastParsedCommand = lastParsedLeaf?.Command;
|
||||||
if (lastParsedLeaf != null && lastParsedCommand != null &&
|
if (lastParsedLeaf != null && lastParsedCommand != null &&
|
||||||
lastParsedCommand.IsBranch && !lastParsedLeaf.ShowHelp &&
|
lastParsedCommand.IsBranch && !lastParsedLeaf.ShowHelp &&
|
||||||
@ -122,7 +125,6 @@ internal sealed class CommandExecutor
|
|||||||
|
|
||||||
return parsedResult;
|
return parsedResult;
|
||||||
}
|
}
|
||||||
#pragma warning restore CS8603 // Possible null reference return.
|
|
||||||
|
|
||||||
private static string ResolveApplicationVersion(IConfiguration configuration)
|
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>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.3" />
|
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<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" });
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user