private async Task ParseCommandFromMatchesAsync(CommandContext context, CommandDelegate next)
        {
            context.Features.Set <IArgumentParserFeature>(new ArgumentParserFeature());

            var matchesFeature        = context.Features.Get <ICommandMatchesFeature>();
            var argumentParserFeature = context.Features.Get <IArgumentParserFeature>();

            if (matchesFeature.HasNoContent() || matchesFeature.CommandMatches.HasNoContent())
            {
                throw new InvalidOperationException($"Can't get command matches from feature: {nameof(ICommandMatchesFeature)}.");
            }

            var bestMatches = new List <ICommandMatch>();

            var fails = new Dictionary <ICommand, IResult>();

            foreach (var match in matchesFeature.CommandMatches)
            {
                var result = await ParseCommandAsync(context, match.Command, match.RemainingInput);

                if (result.Success)
                {
                    bestMatches.Add(match);
                    argumentParserFeature.CommandArgs.Add(match, result.Args.Values.ToArray());
                }
                else
                {
                    fails.Add(match.Command, result);
                }
            }


            if (bestMatches.HasNoContent())
            {
                _logger.LogInformation("All matched commands returned fail for command parsing.");
                context.Result = MiddlewareUtils.GetErrorResult(fails);

                return;
            }

            var config = context.CommandServices.GetRequiredService <IOptions <MariCommandsOptions> >().Value;

            if (!config.ContinueMultiMatchAfterParser)
            {
                bestMatches = bestMatches
                              .OrderByDescending(a => a.Command.Priority)
                              .Take(1)
                              .ToList();

                var bestMatch = bestMatches.FirstOrDefault();

                context.Command = bestMatch.Command;
                context.Alias   = bestMatch.Alias;
                context.Args    = argumentParserFeature.CommandArgs[bestMatch].ToList();
            }

            matchesFeature.CommandMatches = bestMatches;

            await next(context);
        }
        public async Task InvokeAsync(CommandContext context, CommandDelegate next)
        {
            context.NotNull(nameof(context));

            if (context.Result.HasContent())
            {
                await next(context);

                return;
            }

            var isUniqueCommand =
                context.Command.HasContent() &&
                context.Args != null;

            if (isUniqueCommand)
            {
                var result = await ExecutePreconditionsForContextAsync(context);

                if (result.Success)
                {
                    await next(context);
                }
                else
                {
                    context.Result = result;
                }

                return;
            }

            var matchesFeature = context.Features.Get <ICommandMatchesFeature>();

            if (matchesFeature.HasNoContent() || matchesFeature.CommandMatches.HasNoContent())
            {
                throw new InvalidOperationException($"Can't get command matches from feature: {nameof(ICommandMatchesFeature)}.");
            }

            var argumentParserFeature = context.Features.Get <IArgumentParserFeature>();

            if (argumentParserFeature.HasNoContent() || argumentParserFeature.CommandArgs.HasNoContent())
            {
                throw new InvalidOperationException($"Can't get command matches parsed param values from feature: {nameof(IArgumentParserFeature)}.");
            }

            var matches    = matchesFeature.CommandMatches;
            var parsedArgs = argumentParserFeature.CommandArgs;

            var fails       = new Dictionary <ICommand, IResult>();
            var bestMatches = new List <ICommandMatch>();

            foreach (var match in matches)
            {
                var command = match.Command;
                var args    = parsedArgs[match];

                var result = await ExecutePreconditionsAsync(command, args, context);

                if (result.Success)
                {
                    bestMatches.Add(match);
                }
                else
                {
                    fails.Add(command, result);
                }
            }

            if (bestMatches.HasNoContent())
            {
                _logger.LogInformation("All matched commands returned fail for input count.");
                context.Result = MiddlewareUtils.GetErrorResult(fails);

                return;
            }

            matchesFeature.CommandMatches = bestMatches;

            await next(context);
        }
Example #3
0
        public async Task InvokeAsync(CommandContext context, CommandDelegate next)
        {
            context.NotNull(nameof(context));

            if (context.Result.HasContent() || context.Args != null)
            {
                await next(context);

                return;
            }

            var verifyCommandInputCount =
                context.Command.HasContent() &&
                !string.IsNullOrWhiteSpace(context.RawArgs);

            if (verifyCommandInputCount)
            {
                context.Features.Set <ICommandMatchesFeature>(new CommandMatchesFeature
                {
                    CommandMatches = new List <ICommandMatch>
                    {
                        new CommandMatch(context.Command, null, null, context.RawArgs)
                    }
                });
            }

            var matchesFeature = context.Features.Get <ICommandMatchesFeature>();

            if (matchesFeature.HasNoContent() || matchesFeature.CommandMatches.HasNoContent())
            {
                throw new InvalidOperationException($"Can't get command matches from feature: {nameof(ICommandMatchesFeature)}.");
            }

            var multiMatches = new List <ICommandMatch>();

            if (matchesFeature.CommandMatches.Count > 1)
            {
                multiMatches = matchesFeature.CommandMatches
                               .Where(a => a.Command.Module.GetMatchHandling(_config) == MultiMatchHandling.Best)
                               .ToList();
            }
            else
            {
                multiMatches = matchesFeature.CommandMatches.ToList();
            }

            if (multiMatches.HasNoContent())
            {
                _logger.LogInformation($"This input has more than one match but none of then has {MultiMatchHandling.Best} as configuration.");
                context.Result = MultiMatchErrorResult.FromMatches(matchesFeature.CommandMatches);
                return;
            }

            matchesFeature.CommandMatches = multiMatches;

            var bestMatches = new List <ICommandMatch>();

            var fails = new Dictionary <ICommand, IResult>();

            foreach (var match in matchesFeature.CommandMatches)
            {
                var inputCount = string.IsNullOrWhiteSpace(match.RemainingInput)
                    ? 0
                    : match.RemainingInput.Split(_config.Separator).Count();

                var command = match.Command;

                if (command.Parameters.Count > inputCount)
                {
                    var hasAnyOptional = command.Parameters.Any(a => IsOptional(a));

                    if (!hasAnyOptional)
                    {
                        fails.Add(command, BadArgCountResult.FromCommand(command));
                        continue;
                    }

                    var optionalsCount = command.Parameters.Count(a => IsOptional(a));

                    var missingCount = command.Parameters.Count - inputCount;

                    if (optionalsCount < missingCount)
                    {
                        fails.Add(command, BadArgCountResult.FromCommand(command));
                        continue;
                    }
                }
                else if (command.Parameters.Count < inputCount)
                {
                    var ignoreExtraArgs = command.GetIgnoreExtraArgs(_config);

                    if (!ignoreExtraArgs)
                    {
                        fails.Add(command, BadArgCountResult.FromCommand(command));
                        continue;
                    }
                }

                bestMatches.Add(match);
            }

            if (bestMatches.HasNoContent())
            {
                _logger.LogInformation("All matched commands returned fail for input count.");
                context.Result = MiddlewareUtils.GetErrorResult(fails);

                return;
            }

            matchesFeature.CommandMatches = bestMatches;

            await next(context);
        }