fixed line-endings

This commit is contained in:
Nils Andresen
2023-11-27 12:41:08 +01:00
committed by Patrik Svensson
parent 989c0b9904
commit 44300c871f
79 changed files with 2696 additions and 2696 deletions

View File

@ -1,146 +1,146 @@
namespace Spectre.Console.Cli;
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)
{
throw new ArgumentNullException(nameof(configuration));
}
args ??= new List<string>();
_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);
// Asking for version? Kind of a hack, but it's alright.
// We should probably make this a bit better in the future.
if (args.Contains("-v") || args.Contains("--version"))
{
var console = configuration.Settings.Console.GetConsole();
console.WriteLine(ResolveApplicationVersion(configuration));
return 0;
}
// Parse and map the model against the arguments.
var parsedResult = ParseCommandLineArguments(model, configuration.Settings, args);
// Register the arguments with the container.
_registrar.RegisterInstance(typeof(CommandTreeParserResult), parsedResult);
_registrar.RegisterInstance(typeof(IRemainingArguments), parsedResult.Remaining);
// Create the resolver.
using (var resolver = new TypeResolverAdapter(_registrar.Build()))
{
// Get the registered help provider, falling back to the default provider
// if no custom implementations have been registered.
var helpProviders = resolver.Resolve(typeof(IEnumerable<IHelpProvider>)) as IEnumerable<IHelpProvider>;
var helpProvider = helpProviders?.LastOrDefault() ?? new HelpProvider(configuration.Settings);
// Currently the root?
if (parsedResult?.Tree == null)
{
// Display help.
configuration.Settings.Console.SafeRender(helpProvider.Write(model, null));
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(helpProvider.Write(model, leaf.Command));
return leaf.ShowHelp ? 0 : 1;
}
// 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))
{
// Display help for default command.
configuration.Settings.Console.SafeRender(helpProvider.Write(model, leaf.Command));
return 1;
}
// Create the content.
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);
}
}
#pragma warning disable CS8603 // Possible null reference return.
private CommandTreeParserResult ParseCommandLineArguments(CommandModel model, CommandAppSettings settings, IEnumerable<string> args)
{
var parser = new CommandTreeParser(model, settings.CaseSensitivity, settings.ParsingMode, settings.ConvertFlagsToRemainingArguments);
var parserContext = new CommandTreeParserContext(args, settings.ParsingMode);
var tokenizerResult = CommandTreeTokenizer.Tokenize(args);
var parsedResult = parser.Parse(parserContext, tokenizerResult);
var lastParsedLeaf = parsedResult?.Tree?.GetLeafCommand();
var lastParsedCommand = lastParsedLeaf?.Command;
if (lastParsedLeaf != null && lastParsedCommand != null &&
lastParsedCommand.IsBranch && !lastParsedLeaf.ShowHelp &&
lastParsedCommand.DefaultCommand != null)
{
// Insert this branch's default command into the command line
// arguments and try again to see if it will parse.
var argsWithDefaultCommand = new List<string>(args);
argsWithDefaultCommand.Insert(tokenizerResult.Tokens.Position, lastParsedCommand.DefaultCommand.Name);
parserContext = new CommandTreeParserContext(argsWithDefaultCommand, settings.ParsingMode);
tokenizerResult = CommandTreeTokenizer.Tokenize(argsWithDefaultCommand);
parsedResult = parser.Parse(parserContext, tokenizerResult);
}
return parsedResult;
}
#pragma warning restore CS8603 // Possible null reference return.
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);
}
namespace Spectre.Console.Cli;
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)
{
throw new ArgumentNullException(nameof(configuration));
}
args ??= new List<string>();
_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);
// Asking for version? Kind of a hack, but it's alright.
// We should probably make this a bit better in the future.
if (args.Contains("-v") || args.Contains("--version"))
{
var console = configuration.Settings.Console.GetConsole();
console.WriteLine(ResolveApplicationVersion(configuration));
return 0;
}
// Parse and map the model against the arguments.
var parsedResult = ParseCommandLineArguments(model, configuration.Settings, args);
// Register the arguments with the container.
_registrar.RegisterInstance(typeof(CommandTreeParserResult), parsedResult);
_registrar.RegisterInstance(typeof(IRemainingArguments), parsedResult.Remaining);
// Create the resolver.
using (var resolver = new TypeResolverAdapter(_registrar.Build()))
{
// Get the registered help provider, falling back to the default provider
// if no custom implementations have been registered.
var helpProviders = resolver.Resolve(typeof(IEnumerable<IHelpProvider>)) as IEnumerable<IHelpProvider>;
var helpProvider = helpProviders?.LastOrDefault() ?? new HelpProvider(configuration.Settings);
// Currently the root?
if (parsedResult?.Tree == null)
{
// Display help.
configuration.Settings.Console.SafeRender(helpProvider.Write(model, null));
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(helpProvider.Write(model, leaf.Command));
return leaf.ShowHelp ? 0 : 1;
}
// 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))
{
// Display help for default command.
configuration.Settings.Console.SafeRender(helpProvider.Write(model, leaf.Command));
return 1;
}
// Create the content.
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);
}
}
#pragma warning disable CS8603 // Possible null reference return.
private CommandTreeParserResult ParseCommandLineArguments(CommandModel model, CommandAppSettings settings, IEnumerable<string> args)
{
var parser = new CommandTreeParser(model, settings.CaseSensitivity, settings.ParsingMode, settings.ConvertFlagsToRemainingArguments);
var parserContext = new CommandTreeParserContext(args, settings.ParsingMode);
var tokenizerResult = CommandTreeTokenizer.Tokenize(args);
var parsedResult = parser.Parse(parserContext, tokenizerResult);
var lastParsedLeaf = parsedResult?.Tree?.GetLeafCommand();
var lastParsedCommand = lastParsedLeaf?.Command;
if (lastParsedLeaf != null && lastParsedCommand != null &&
lastParsedCommand.IsBranch && !lastParsedLeaf.ShowHelp &&
lastParsedCommand.DefaultCommand != null)
{
// Insert this branch's default command into the command line
// arguments and try again to see if it will parse.
var argsWithDefaultCommand = new List<string>(args);
argsWithDefaultCommand.Insert(tokenizerResult.Tokens.Position, lastParsedCommand.DefaultCommand.Name);
parserContext = new CommandTreeParserContext(argsWithDefaultCommand, settings.ParsingMode);
tokenizerResult = CommandTreeTokenizer.Tokenize(argsWithDefaultCommand);
parsedResult = parser.Parse(parserContext, tokenizerResult);
}
return parsedResult;
}
#pragma warning restore CS8603 // Possible null reference return.
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);
}
}

View File

@ -1,4 +1,4 @@
namespace Spectre.Console.Cli;
namespace Spectre.Console.Cli;
internal sealed class BranchConfigurator : IBranchConfigurator
{

View File

@ -5,16 +5,16 @@ internal sealed class CommandAppSettings : ICommandAppSettings
public CultureInfo? Culture { get; set; }
public string? ApplicationName { get; set; }
public string? ApplicationVersion { get; set; }
public int MaximumIndirectExamples { get; set; }
public bool ShowOptionDefaultValues { get; set; }
public int MaximumIndirectExamples { get; set; }
public bool ShowOptionDefaultValues { get; set; }
public IAnsiConsole? Console { get; set; }
public ICommandInterceptor? Interceptor { get; set; }
public ITypeRegistrarFrontend Registrar { get; set; }
public CaseSensitivity CaseSensitivity { get; set; }
public bool PropagateExceptions { get; set; }
public bool ValidateExamples { get; set; }
public bool TrimTrailingPeriod { get; set; } = true;
public bool StrictParsing { get; set; }
public bool TrimTrailingPeriod { get; set; } = true;
public bool StrictParsing { get; set; }
public bool ConvertFlagsToRemainingArguments { get; set; } = false;
public ParsingMode ParsingMode =>
@ -26,7 +26,7 @@ internal sealed class CommandAppSettings : ICommandAppSettings
{
Registrar = new TypeRegistrar(registrar);
CaseSensitivity = CaseSensitivity.All;
ShowOptionDefaultValues = true;
ShowOptionDefaultValues = true;
MaximumIndirectExamples = 5;
}

View File

@ -19,19 +19,19 @@ internal sealed class Configurator : IUnsafeConfigurator, IConfigurator, IConfig
Settings = new CommandAppSettings(registrar);
Examples = new List<string[]>();
}
public void SetHelpProvider(IHelpProvider helpProvider)
{
// Register the help provider
_registrar.RegisterInstance(typeof(IHelpProvider), helpProvider);
}
public void SetHelpProvider<T>()
where T : IHelpProvider
{
// Register the help provider
_registrar.Register(typeof(IHelpProvider), typeof(T));
}
public void SetHelpProvider(IHelpProvider helpProvider)
{
// Register the help provider
_registrar.RegisterInstance(typeof(IHelpProvider), helpProvider);
}
public void SetHelpProvider<T>()
where T : IHelpProvider
{
// Register the help provider
_registrar.Register(typeof(IHelpProvider), typeof(T));
}
public void AddExample(params string[] args)
{

View File

@ -1,5 +1,5 @@
namespace Spectre.Console.Cli;
internal sealed class CommandInfo : ICommandContainer, ICommandInfo
{
public string Name { get; }
@ -20,14 +20,14 @@ internal sealed class CommandInfo : ICommandContainer, ICommandInfo
// only branches can have a default command
public CommandInfo? DefaultCommand => IsBranch ? Children.FirstOrDefault(c => c.IsDefaultCommand) : null;
public bool IsHidden { get; }
IReadOnlyList<ICommandInfo> Help.ICommandContainer.Commands => Children.Cast<ICommandInfo>().ToList();
ICommandInfo? Help.ICommandContainer.DefaultCommand => DefaultCommand;
IReadOnlyList<ICommandParameter> ICommandInfo.Parameters => Parameters.Cast<ICommandParameter>().ToList();
ICommandInfo? ICommandInfo.Parent => Parent;
IReadOnlyList<string[]> Help.ICommandContainer.Examples => (IReadOnlyList<string[]>)Examples;
public bool IsHidden { get; }
IReadOnlyList<ICommandInfo> Help.ICommandContainer.Commands => Children.Cast<ICommandInfo>().ToList();
ICommandInfo? Help.ICommandContainer.DefaultCommand => DefaultCommand;
IReadOnlyList<ICommandParameter> ICommandInfo.Parameters => Parameters.Cast<ICommandParameter>().ToList();
ICommandInfo? ICommandInfo.Parent => Parent;
IReadOnlyList<string[]> Help.ICommandContainer.Examples => (IReadOnlyList<string[]>)Examples;
public CommandInfo(CommandInfo? parent, ConfiguredCommand prototype)
{
Parent = parent;
@ -54,5 +54,5 @@ internal sealed class CommandInfo : ICommandContainer, ICommandInfo
Description = description.Description;
}
}
}
}
}

View File

@ -1,17 +1,17 @@
namespace Spectre.Console.Cli;
internal sealed class CommandModel : ICommandContainer, ICommandModel
{
public string? ApplicationName { get; }
public ParsingMode ParsingMode { get; }
public IList<CommandInfo> Commands { get; }
public IList<string[]> Examples { get; }
public IList<string[]> Examples { get; }
public CommandInfo? DefaultCommand => Commands.FirstOrDefault(c => c.IsDefaultCommand);
string ICommandModel.ApplicationName => GetApplicationName(ApplicationName);
IReadOnlyList<ICommandInfo> Help.ICommandContainer.Commands => Commands.Cast<ICommandInfo>().ToList();
ICommandInfo? Help.ICommandContainer.DefaultCommand => DefaultCommand;
ICommandInfo? Help.ICommandContainer.DefaultCommand => DefaultCommand;
IReadOnlyList<string[]> Help.ICommandContainer.Examples => (IReadOnlyList<string[]>)Examples;
public CommandModel(
@ -22,18 +22,18 @@ internal sealed class CommandModel : ICommandContainer, ICommandModel
ApplicationName = settings.ApplicationName;
ParsingMode = settings.ParsingMode;
Commands = new List<CommandInfo>(commands ?? Array.Empty<CommandInfo>());
Examples = new List<string[]>(examples ?? Array.Empty<string[]>());
}
/// <summary>
/// Gets the name of the application.
/// If the provided <paramref name="applicationName"/> is not null or empty,
/// it is returned. Otherwise the name of the current application
/// is determined based on the executable file's name.
/// </summary>
/// <param name="applicationName">The optional name of the application.</param>
/// <returns>
/// The name of the application, or a default value of "?" if no valid application name can be determined.
Examples = new List<string[]>(examples ?? Array.Empty<string[]>());
}
/// <summary>
/// Gets the name of the application.
/// If the provided <paramref name="applicationName"/> is not null or empty,
/// it is returned. Otherwise the name of the current application
/// is determined based on the executable file's name.
/// </summary>
/// <param name="applicationName">The optional name of the application.</param>
/// <returns>
/// The name of the application, or a default value of "?" if no valid application name can be determined.
/// </returns>
private static string GetApplicationName(string? applicationName)
{
@ -45,7 +45,7 @@ internal sealed class CommandModel : ICommandContainer, ICommandModel
private static string? GetApplicationFile()
{
var location = Assembly.GetEntryAssembly()?.Location;
var location = Assembly.GetEntryAssembly()?.Location;
if (string.IsNullOrWhiteSpace(location))
{

View File

@ -1,5 +1,5 @@
namespace Spectre.Console.Cli;
internal static class CommandModelBuilder
{
// Consider removing this in favor for value tuples at some point.
@ -31,8 +31,8 @@ internal static class CommandModelBuilder
configuration.DefaultCommand.Examples.AddRange(configuration.Examples);
// Build the default command.
var defaultCommand = Build(null, configuration.DefaultCommand);
var defaultCommand = Build(null, configuration.DefaultCommand);
result.Add(defaultCommand);
}
@ -55,7 +55,7 @@ internal static class CommandModelBuilder
foreach (var childCommand in command.Children)
{
var child = Build(info, childCommand);
info.Children.Add(child);
info.Children.Add(child);
}
// Normalize argument positions.

View File

@ -1,5 +1,5 @@
namespace Spectre.Console.Cli;
internal abstract class CommandParameter : ICommandParameterInfo, ICommandParameter
{
public Guid Id { get; }
@ -17,10 +17,10 @@ internal abstract class CommandParameter : ICommandParameterInfo, ICommandParame
public string PropertyName => Property.Name;
public virtual bool WantRawValue => ParameterType.IsPairDeconstructable()
&& (PairDeconstructor != null || Converter == null);
public bool IsFlag => ParameterKind == ParameterKind.Flag;
&& (PairDeconstructor != null || Converter == null);
public bool IsFlag => ParameterKind == ParameterKind.Flag;
protected CommandParameter(
Type parameterType, ParameterKind parameterKind, PropertyInfo property,
string? description, TypeConverterAttribute? converter,

View File

@ -8,13 +8,13 @@ internal interface ICommandContainer
/// <summary>
/// Gets all commands in the container.
/// </summary>
IList<CommandInfo> Commands { get; }
IList<CommandInfo> Commands { get; }
/// <summary>
/// Gets the default command for the container.
/// </summary>
/// <remarks>
/// Returns null if a default command has not been set.
/// </remarks>
/// </summary>
/// <remarks>
/// Returns null if a default command has not been set.
/// </remarks>
CommandInfo? DefaultCommand { get; }
}

View File

@ -1,12 +1,12 @@
using static Spectre.Console.Cli.CommandTreeTokenizer;
using static Spectre.Console.Cli.CommandTreeTokenizer;
namespace Spectre.Console.Cli;
internal class CommandTreeParser
{
private readonly CommandModel _configuration;
private readonly ParsingMode _parsingMode;
private readonly CommandOptionAttribute _help;
private readonly CommandOptionAttribute _help;
private readonly bool _convertFlagsToRemainingArguments;
public CaseSensitivity CaseSensitivity { get; }
@ -21,20 +21,20 @@ internal class CommandTreeParser
{
_configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
_parsingMode = parsingMode ?? _configuration.ParsingMode;
_help = new CommandOptionAttribute("-h|--help");
_help = new CommandOptionAttribute("-h|--help");
_convertFlagsToRemainingArguments = convertFlagsToRemainingArguments ?? false;
CaseSensitivity = caseSensitivity;
}
}
public CommandTreeParserResult Parse(IEnumerable<string> args)
{
var parserContext = new CommandTreeParserContext(args, _parsingMode);
var tokenizerResult = CommandTreeTokenizer.Tokenize(args);
return Parse(parserContext, tokenizerResult);
}
{
var parserContext = new CommandTreeParserContext(args, _parsingMode);
var tokenizerResult = CommandTreeTokenizer.Tokenize(args);
return Parse(parserContext, tokenizerResult);
}
public CommandTreeParserResult Parse(CommandTreeParserContext context, CommandTreeTokenizerResult tokenizerResult)
{
var tokens = tokenizerResult.Tokens;
@ -258,8 +258,8 @@ internal class CommandTreeParser
// Find the option.
var option = node.FindOption(token.Value, isLongOption, CaseSensitivity);
if (option != null)
{
ParseOptionValue(context, stream, token, node, option);
{
ParseOptionValue(context, stream, token, node, option);
return;
}
@ -291,10 +291,10 @@ internal class CommandTreeParser
CommandTreeParserContext context,
CommandTreeTokenStream stream,
CommandTreeToken token,
CommandTree current,
CommandTree current,
CommandParameter? parameter = null)
{
bool addToMappedCommandParameters = parameter != null;
{
bool addToMappedCommandParameters = parameter != null;
var value = default(string);
@ -312,49 +312,49 @@ internal class CommandTreeParser
{
// Is this a command?
if (current.Command.FindCommand(valueToken.Value, CaseSensitivity) == null)
{
if (parameter != null)
{
if (parameter.ParameterKind == ParameterKind.Flag)
{
if (!CliConstants.AcceptedBooleanValues.Contains(valueToken.Value, StringComparer.OrdinalIgnoreCase))
{
if (!valueToken.HadSeparator)
{
// Do nothing
// - assume valueToken is unrelated to the flag parameter (ie. we've parsed it unnecessarily)
// - rely on the "No value?" code below to set the flag to its default value
// - valueToken will be handled on the next pass of the parser
}
else
{
// Flags cannot be assigned a value.
if (_convertFlagsToRemainingArguments)
{
value = stream.Consume(CommandTreeToken.Kind.String)?.Value;
context.AddRemainingArgument(token.Value, value);
// Prevent the option and it's non-boolean value from being added to
// mapped parameters (otherwise an exception will be thrown later
// when binding the value to the flag in the comand settings)
addToMappedCommandParameters = false;
}
else
{
throw CommandParseException.CannotAssignValueToFlag(context.Arguments, token);
}
}
}
else
{
value = stream.Consume(CommandTreeToken.Kind.String)?.Value;
}
}
else
{
value = stream.Consume(CommandTreeToken.Kind.String)?.Value;
}
{
if (parameter != null)
{
if (parameter.ParameterKind == ParameterKind.Flag)
{
if (!CliConstants.AcceptedBooleanValues.Contains(valueToken.Value, StringComparer.OrdinalIgnoreCase))
{
if (!valueToken.HadSeparator)
{
// Do nothing
// - assume valueToken is unrelated to the flag parameter (ie. we've parsed it unnecessarily)
// - rely on the "No value?" code below to set the flag to its default value
// - valueToken will be handled on the next pass of the parser
}
else
{
// Flags cannot be assigned a value.
if (_convertFlagsToRemainingArguments)
{
value = stream.Consume(CommandTreeToken.Kind.String)?.Value;
context.AddRemainingArgument(token.Value, value);
// Prevent the option and it's non-boolean value from being added to
// mapped parameters (otherwise an exception will be thrown later
// when binding the value to the flag in the comand settings)
addToMappedCommandParameters = false;
}
else
{
throw CommandParseException.CannotAssignValueToFlag(context.Arguments, token);
}
}
}
else
{
value = stream.Consume(CommandTreeToken.Kind.String)?.Value;
}
}
else
{
value = stream.Consume(CommandTreeToken.Kind.String)?.Value;
}
}
else
{
@ -370,13 +370,13 @@ internal class CommandTreeParser
}
}
else
{
{
context.AddRemainingArgument(token.Value, parseValue ? valueToken.Value : null);
}
}
else
{
if (parameter == null && // Only add tokens which have not been matched to a command parameter
if (parameter == null && // Only add tokens which have not been matched to a command parameter
(context.State == State.Remaining || context.ParsingMode == ParsingMode.Relaxed))
{
context.AddRemainingArgument(token.Value, null);
@ -399,10 +399,10 @@ internal class CommandTreeParser
if (parameter.IsFlagValue())
{
value = null;
}
else
{
throw CommandParseException.OptionHasNoValue(context.Arguments, token, option);
}
else
{
throw CommandParseException.OptionHasNoValue(context.Arguments, token, option);
}
}
else
@ -415,9 +415,9 @@ internal class CommandTreeParser
}
}
if (parameter != null && addToMappedCommandParameters)
{
current.Mapped.Add(new MappedCommandParameter(parameter, value));
if (parameter != null && addToMappedCommandParameters)
{
current.Mapped.Add(new MappedCommandParameter(parameter, value));
}
}
}

View File

@ -26,15 +26,15 @@ internal class CommandTreeParserContext
public void IncreaseArgumentPosition()
{
CurrentArgumentPosition++;
}
}
public void AddRemainingArgument(string key, string? value)
{
if (!_remaining.ContainsKey(key))
{
_remaining.Add(key, new List<string?>());
}
{
if (!_remaining.ContainsKey(key))
{
_remaining.Add(key, new List<string?>());
}
_remaining[key].Add(value);
}

View File

@ -6,11 +6,11 @@ internal sealed class CommandTreeToken
public int Position { get; }
public string Value { get; }
public string Representation { get; }
public bool IsGrouped { get; set; }
/// <summary>
/// Gets or sets a value indicating whether a separater was encountered immediately before the <see cref="CommandTreeToken.Value"/>.
/// </summary>
public bool IsGrouped { get; set; }
/// <summary>
/// Gets or sets a value indicating whether a separater was encountered immediately before the <see cref="CommandTreeToken.Value"/>.
/// </summary>
public bool HadSeparator { get; set; }
public enum Kind

View File

@ -5,7 +5,7 @@ internal sealed class CommandTreeTokenStream : IReadOnlyList<CommandTreeToken>
private readonly List<CommandTreeToken> _tokens;
private int _position;
public int Count => _tokens.Count;
public int Count => _tokens.Count;
public int Position => _position;
public CommandTreeToken this[int index] => _tokens[index];

View File

@ -29,13 +29,13 @@ internal static class CommandTreeTokenizer
var context = new CommandTreeTokenizerContext();
foreach (var arg in args)
{
if (string.IsNullOrEmpty(arg))
{
// Null strings in the args array are still represented as tokens
tokens.Add(new CommandTreeToken(CommandTreeToken.Kind.String, position, string.Empty, string.Empty));
continue;
}
{
if (string.IsNullOrEmpty(arg))
{
// Null strings in the args array are still represented as tokens
tokens.Add(new CommandTreeToken(CommandTreeToken.Kind.String, position, string.Empty, string.Empty));
continue;
}
var start = position;
var reader = new TextBuffer(previousReader, arg);
@ -55,30 +55,30 @@ internal static class CommandTreeTokenizer
}
private static int ParseToken(CommandTreeTokenizerContext context, TextBuffer reader, int position, int start, List<CommandTreeToken> tokens)
{
if (!reader.ReachedEnd && reader.Peek() == '-')
{
// Option
tokens.AddRange(ScanOptions(context, reader));
}
else
{
// Command or argument
while (reader.Peek() != -1)
{
if (reader.ReachedEnd)
{
position += reader.Position - start;
break;
}
tokens.Add(ScanString(context, reader));
// Flush remaining tokens
context.FlushRemaining();
}
}
{
if (!reader.ReachedEnd && reader.Peek() == '-')
{
// Option
tokens.AddRange(ScanOptions(context, reader));
}
else
{
// Command or argument
while (reader.Peek() != -1)
{
if (reader.ReachedEnd)
{
position += reader.Position - start;
break;
}
tokens.Add(ScanString(context, reader));
// Flush remaining tokens
context.FlushRemaining();
}
}
return position;
}
@ -102,7 +102,7 @@ internal static class CommandTreeTokenizer
builder.Append(current);
}
var value = builder.ToString();
var value = builder.ToString();
return new CommandTreeToken(CommandTreeToken.Kind.String, position, value, value);
}
@ -149,8 +149,8 @@ internal static class CommandTreeTokenizer
var token = new CommandTreeToken(CommandTreeToken.Kind.String, reader.Position, "=", "=");
throw CommandParseException.OptionValueWasExpected(reader.Original, token);
}
var tokenValue = ScanString(context, reader);
var tokenValue = ScanString(context, reader);
tokenValue.HadSeparator = true;
result.Add(tokenValue);
}
@ -193,7 +193,7 @@ internal static class CommandTreeTokenizer
// be tokenized as strings. This block handles parsing those cases, but we only allow this
// when the digit is the first character in the token (i.e. "-a1" is always an error), hence the
// result.Count == 0 check above.
string value = string.Empty;
string value = string.Empty;
while (!reader.ReachedEnd)
{
@ -212,12 +212,12 @@ internal static class CommandTreeTokenizer
result.Add(new CommandTreeToken(CommandTreeToken.Kind.String, position, value, value));
}
else
{
{
// Create a token representing the short option.
var representation = current.ToString(CultureInfo.InvariantCulture);
var tokenPosition = position + 1 + result.Count;
var token = new CommandTreeToken(CommandTreeToken.Kind.ShortOption, tokenPosition, representation, representation);
var representation = current.ToString(CultureInfo.InvariantCulture);
var tokenPosition = position + 1 + result.Count;
var token = new CommandTreeToken(CommandTreeToken.Kind.ShortOption, tokenPosition, representation, representation);
throw CommandParseException.InvalidShortOptionName(reader.Original, token);
}
}