/// <summary>
        /// Converts the command tree to a set of Discord application commands.
        /// </summary>
        /// <param name="tree">The command tree.</param>
        /// <param name="commands">The created commands, if any.</param>
        /// <returns>A creation result which may or may not have succeeded.</returns>
        public static CreateCommandResult CreateApplicationCommands
        (
            this CommandTree tree,
            [NotNullWhen(true)] out IReadOnlyList <IApplicationCommandOption>?commands
        )
        {
            commands = null;

            var createdCommands = new List <IApplicationCommandOption>();

            foreach (var child in tree.Root.Children)
            {
                var createOption = ToOption(child, out var option);
                if (!createOption.IsSuccess)
                {
                    return(createOption);
                }

                createdCommands.Add(option !);
            }

            if (createdCommands.Count > MaxRootCommandsOrGroups)
            {
                return(CreateCommandResult.FromError("Too many root-level commands or groups."));
            }

            if (createdCommands.GroupBy(c => c.Name).Any(g => g.Count() > 1))
            {
                return(CreateCommandResult.FromError("Overloads are not supported."));
            }

            commands = createdCommands;
            return(CreateCommandResult.FromSuccess());
        }
Ejemplo n.º 2
0
    private CommandTree ParseCommandParameters(
        CommandTreeParserContext context,
        CommandInfo command,
        CommandTree?parent,
        CommandTreeTokenStream stream)
    {
        context.ResetArgumentPosition();

        var node = new CommandTree(parent, command);

        while (stream.Peek() != null)
        {
            var token = stream.Peek();
            if (token == null)
            {
                // Should not happen, but the compiler isn't
                // smart enough to realize this...
                throw new CommandRuntimeException("Could not get the next token.");
            }

            switch (token.TokenKind)
            {
            case CommandTreeToken.Kind.LongOption:
                // Long option
                ParseOption(context, stream, token, node, true);
                break;

            case CommandTreeToken.Kind.ShortOption:
                // Short option
                ParseOption(context, stream, token, node, false);
                break;

            case CommandTreeToken.Kind.String:
                // Command
                ParseString(context, stream, node);
                break;

            case CommandTreeToken.Kind.Remaining:
                // Remaining
                stream.Consume(CommandTreeToken.Kind.Remaining);
                context.State = State.Remaining;
                break;

            default:
                throw new InvalidOperationException($"Encountered unknown token ({token.TokenKind}).");
            }
        }

        // Add unmapped parameters.
        foreach (var parameter in node.Command.Parameters)
        {
            if (node.Mapped.All(m => m.Parameter != parameter))
            {
                node.Unmapped.Add(parameter);
            }
        }

        return(node);
    }
Ejemplo n.º 3
0
 public static RuntimeException MissingRequiredArgument(CommandTree node, CommandArgument argument)
 {
     if (node.Command.Name == Constants.DefaultCommandName)
     {
         return(new RuntimeException($"Missing required argument '{argument.Value}'."));
     }
     return(new RuntimeException($"Command '{node.Command.Name}' is missing required argument '{argument.Value}'."));
 }
Ejemplo n.º 4
0
 public static CommandOption?FindOption(this CommandTree tree, string name, bool longOption, CaseSensitivity sensitivity)
 {
     return(tree.Command.Parameters
            .OfType <CommandOption>()
            .FirstOrDefault(o => longOption
             ? o.LongNames.Contains(name, sensitivity.GetStringComparer(CommandPart.LongOption))
             : o.ShortNames.Contains(name, StringComparer.Ordinal)));
 }
Ejemplo n.º 5
0
    public static CommandTree GetLeafCommand(this CommandTree node)
    {
        while (node.Next != null)
        {
            node = node.Next;
        }

        return(node);
    }
Ejemplo n.º 6
0
        public static ParseException UnknownCommand(CommandModel model, CommandTree node, IEnumerable <string> args, CommandTreeToken token)
        {
            var availableCommands = node?.Command ?? (ICommandContainer)model;
            var suggestion        = CommandSuggestor.Suggest(model, node?.Command, token.Value);

            var text = suggestion != null ? $"Did you mean '{suggestion.Name}'?" : "No such command.";

            return(ParseExceptionFactory.Create(args, token, $"Unknown command '{token.Value}'.", text));
        }
Ejemplo n.º 7
0
    public static CommandTree?GetRootCommand(this CommandTree node)
    {
        while (node.Parent != null)
        {
            node = node.Parent;
        }

        return(node);
    }
        public static XmlDocument Serialize(CommandTree tree)
        {
            var document = new XmlDocument();
            var root     = document.CreateElement("model");

            root.AppendChild(document.CreateComment(tree.Command.Name.ToUpperInvariant()));
            root.AppendChild(Serialize(document, tree));
            document.AppendChild(root);
            return(document);
        }
Ejemplo n.º 9
0
 /// <summary>
 /// Initializes a new instance of the <see cref="SlashService"/> class.
 /// </summary>
 /// <param name="commandTree">The command tree.</param>
 /// <param name="oauth2API">The OAuth2 API.</param>
 /// <param name="applicationAPI">The application API.</param>
 public SlashService
 (
     CommandTree commandTree,
     IDiscordRestOAuth2API oauth2API,
     IDiscordRestApplicationAPI applicationAPI
 )
 {
     _commandTree    = commandTree;
     _applicationAPI = applicationAPI;
     _oauth2API      = oauth2API;
 }
Ejemplo n.º 10
0
        public static CommandTree GetTree()
        {
            if (commandtree != null)
            {
                return(commandtree);
            }

            commandtree = new CommandTree();
            treeService.AddLeaf(commandtree, typeof(DefaultCommandContainer).FullName, new DefaultCommandContainer());
            return(commandtree);
        }
        List <string> BuildInterface(CommandTree tree, int subtreeDepth = 0)
        {
            List <string> lines;
            int           subtreeIndex = subtreeIndexAtDepth[subtreeDepth];
            int           maxDepth     = subtreeIndexAtDepth.Count - 1;

            // If there's a index greater than where we are now,
            // don't try to render this command tree, but instead render the next one.
            if (maxDepth > subtreeDepth)
            {
                lines = BuildInterface(tree.subtrees[subtreeIndex - tree.commands.Count], subtreeDepth + 1);
                if (lines.Count < 9)
                {
                    lines.Insert(0, "|| " + tree.label + $" [{subtreeIndex}]");
                }
                return(lines);
            }
            lines = new List <string>()
            {
                "|| " + tree.label + $" [{subtreeIndex}]"
            };
            for (int i = 0; i < tree.commands.Count; i++)
            {
                if (subtreeIndex - i > 5)
                {
                    continue;
                }
                if (i == subtreeIndex)
                {
                    lines.Add("|> " + tree.commands[i].label);
                }
                else
                {
                    lines.Add("|  " + tree.commands[i].label);
                }
            }
            for (int i = 0; i < tree.subtrees.Count; i++)
            {
                var commandIndex = subtreeIndex - tree.commands.Count;
                if (commandIndex - i > 5)
                {
                    continue;
                }
                if (i == commandIndex)
                {
                    lines.Add("|> " + tree.subtrees[i].label);
                }
                else
                {
                    lines.Add("|  " + tree.subtrees[i].label);
                }
            }
            return(lines);
        }
 public static IServiceCollection AddCommandTree(this IServiceCollection services, Action <CommandTree> addCommands)
 {
     return(services.AddScoped <IScopedShellCommand, ScopedCommand>()
            .AddSingleton <ICommandTree, CommandTree>(_ =>
     {
         var commandTree = new CommandTree();
         addCommands(commandTree);
         return commandTree;
     })
            .AddHostedService <CommandService>());
 }
        public PanelCommander(CommandTree root, IMyTextSurface outputSurface)
        {
            this.root = root;
            this.subtreeIndexAtDepth = new List <int>()
            {
                0
            };
            this.outputSurface = outputSurface;

            Draw();
        }
        CommandTree GetCurrentSubtree(CommandTree tree, int depth = 0)
        {
            int subtreeIndex = subtreeIndexAtDepth[depth];
            int maxDepth     = subtreeIndexAtDepth.Count - 1;

            if (maxDepth > depth)
            {
                return(tree.subtrees[subtreeIndex - tree.commands.Count]);
            }
            return(tree);
        }
Ejemplo n.º 15
0
        private int Execute(CommandTree leaf, CommandTree tree, ILookup <string, string> remaining, ITypeResolver resolver)
        {
            // Create the command and the settings.
            var settings = leaf.CreateSettings(resolver);

            // Bind the command tree against the settings.
            _binder.Bind(tree, ref settings, resolver);

            // Execute the command.
            var command = leaf.CreateCommand(resolver);

            return(command.Execute(settings, remaining));
        }
 void Select(CommandTree commandTree, int index)
 {
     // it's a command
     if (index < commandTree.commands.Count)
     {
         commandTree.commands[index].action();
     }
     else
     // it's a subtree
     {
         subtreeIndexAtDepth.Add(0);
     }
 }
Ejemplo n.º 17
0
        internal MethodExpression(CommandTree cmdTree, MethodMetadata methodInfo, IList <Expression> args, Expression instance)
            : base(cmdTree, ExpressionKind.Method)
        {
            //
            // Ensure that the property metadata is non-null and from the same metadata workspace and dataspace as the command tree.
            //
            CommandTreeTypeHelper.CheckMember(methodInfo, "method", "methodInfo");

            //
            // Methods that return void are not allowed
            //
            if (cmdTree.TypeHelper.IsNullOrNullType(methodInfo.Type))
            {
                throw EntityUtil.Argument(System.Data.Entity.Strings.Cqt_Method_VoidResultInvalid, "methodInfo");
            }

            if (null == args)
            {
                throw EntityUtil.ArgumentNull("args");
            }

            this.m_inst = new ExpressionLink("Instance", cmdTree);

            //
            // Validate the instance
            //
            if (methodInfo.IsStatic)
            {
                if (instance != null)
                {
                    throw EntityUtil.Argument(System.Data.Entity.Strings.Cqt_Method_InstanceInvalidForStatic, "instance");
                }
            }
            else
            {
                if (null == instance)
                {
                    throw EntityUtil.Argument(System.Data.Entity.Strings.Cqt_Method_InstanceRequiredForInstance, "instance");
                }

                this.m_inst.SetExpectedType(methodInfo.DefiningType);
                this.m_inst.InitializeValue(instance);
            }

            //
            // Validate the arguments
            //
            m_args          = new ExpressionList("Arguments", cmdTree, methodInfo.Parameters, args);
            m_methodInfo    = methodInfo;
            this.ResultType = methodInfo.Type;
        }
Ejemplo n.º 18
0
            public void Setup()
            {
                // The creation of a CommandTree is complicated. To keep the test simple, the CommandTreeBuilder is used.
                // The tradeoff is that if the CommandTreeBuilder does not work correctly, this test might fail even though
                // the CommandTree itself works correctly. Since the Builder itself is tested, I find this acceptable.

                var mock = new Mock <ICommandGroupAssemblyProvider>();

                mock.Setup(q => q.GetAssemblies())
                .Returns(new Assembly[]
                {
                    Assembly.GetExecutingAssembly()
                });

                _tree = new CommandTreeBuilder(mock.Object).BuildBaseTree();
            }
Ejemplo n.º 19
0
    private void ParseOption(
        CommandTreeParserContext context,
        CommandTreeTokenStream stream,
        CommandTreeToken token,
        CommandTree node,
        bool isLongOption)
    {
        // Consume the option token.
        stream.Consume(isLongOption ? CommandTreeToken.Kind.LongOption : CommandTreeToken.Kind.ShortOption);

        if (context.State == State.Normal)
        {
            // Find the option.
            var option = node.FindOption(token.Value, isLongOption, CaseSensitivity);
            if (option != null)
            {
                node.Mapped.Add(new MappedCommandParameter(
                                    option, ParseOptionValue(context, stream, token, node, option)));

                return;
            }

            // Help?
            if (_help?.IsMatch(token.Value) == true)
            {
                node.ShowHelp = true;
                return;
            }
        }

        if (context.State == State.Remaining)
        {
            ParseOptionValue(context, stream, token, node, null);
            return;
        }

        if (context.ParsingMode == ParsingMode.Strict)
        {
            throw CommandParseException.UnknownOption(context.Arguments, token);
        }
        else
        {
            ParseOptionValue(context, stream, token, node, null);
        }
    }
Ejemplo n.º 20
0
    public static bool IsOptionMappedWithParent(this CommandTree tree, string name, bool longOption)
    {
        var node = tree.Parent;

        while (node != null)
        {
            var option = node.Command?.Parameters.OfType <CommandOption>()
                         .FirstOrDefault(o => longOption
                    ? o.LongNames.Contains(name, StringComparer.Ordinal)
                    : o.ShortNames.Contains(name, StringComparer.Ordinal));

            if (option != null)
            {
                return(node.Mapped.Any(p => p.Parameter == option));
            }

            node = node.Parent;
        }

        return(false);
    }
Ejemplo n.º 21
0
 public MessageCreated(LastMessageCacheService lastMessageCache, LoggerCleanService loggerClean,
                       IMetrics metrics, ProxyService proxy,
                       CommandTree tree, ILifetimeScope services, IDatabase db, BotConfig config,
                       ModelRepository repo, IDiscordCache cache,
                       Bot bot, Cluster cluster, DiscordApiClient rest, PrivateChannelService dmCache)
 {
     _lastMessageCache = lastMessageCache;
     _loggerClean      = loggerClean;
     _metrics          = metrics;
     _proxy            = proxy;
     _tree             = tree;
     _services         = services;
     _db      = db;
     _config  = config;
     _repo    = repo;
     _cache   = cache;
     _bot     = bot;
     _cluster = cluster;
     _rest    = rest;
     _dmCache = dmCache;
 }
Ejemplo n.º 22
0
        private static XmlNode Serialize(XmlDocument doc, CommandTree tree)
        {
            var node = doc.CreateElement("command");

            // Attributes
            node.SetNullableAttribute("name", tree.Command.Name);
            node.SetBooleanAttribute("help", tree.ShowHelp);

            // Mapped
            if (tree.Mapped.Count > 0)
            {
                var parameterRootNode = doc.CreateElement("mapped");
                foreach (var parameter in CreateMappedParameterNodes(doc, tree.Mapped))
                {
                    parameterRootNode.AppendChild(parameter);
                }
                node.AppendChild(parameterRootNode);
            }

            // Unmapped
            if (tree.Unmapped.Count > 0)
            {
                var parameterRootNode = doc.CreateElement("unmapped");
                foreach (var parameter in CreateUnmappedParameterNodes(doc, tree.Unmapped))
                {
                    parameterRootNode.AppendChild(parameter);
                }
                node.AppendChild(parameterRootNode);
            }

            // Command
            if (tree.Next != null)
            {
                node.AppendChild(doc.CreateComment(tree.Next.Command.Name.ToUpperInvariant()));
                node.AppendChild(Serialize(doc, tree.Next));
            }

            return(node);
        }
Ejemplo n.º 23
0
        private static void ValidateRequiredParameters(CommandTree tree)
        {
            var node = tree.GetRootCommand();

            while (node != null)
            {
                foreach (var parameter in node.Unmapped)
                {
                    if (parameter.Required)
                    {
                        switch (parameter)
                        {
                        case CommandOption option:
                            throw new CommandAppException($"Command '{node.Command.Name}' is missing required option '{option.GetOptionName()}'.");

                        case CommandArgument argument:
                            throw new CommandAppException($"Command '{node.Command.Name}' is missing required argument '{argument.Value}'.");
                        }
                    }
                }
                node = node.Next;
            }
        }
Ejemplo n.º 24
0
        public void Bind(CommandTree tree, ref object obj, ITypeResolver resolver)
        {
            ValidateRequiredParameters(tree);

            TypeConverter GetConverter(CommandParameter parameter)
            {
                if (parameter.Converter == null)
                {
                    return(TypeDescriptor.GetConverter(parameter.ParameterType));
                }
                var type = Type.GetType(parameter.Converter.ConverterTypeName);

                return(resolver.Resolve(type) as TypeConverter);
            }

            while (tree != null)
            {
                // Process mapped parameters.
                foreach (var(parameter, value) in tree.Mapped)
                {
                    var converter = GetConverter(parameter);
                    parameter.Assign(obj, converter.ConvertFromInvariantString(value));
                }

                // Process unmapped parameters.
                foreach (var parameter in tree.Unmapped)
                {
                    // Is this an option with a default value?
                    if (parameter is CommandOption option && option.DefaultValue != null)
                    {
                        parameter.Assign(obj, option.DefaultValue.Value);
                    }
                }

                tree = tree.Next;
            }
        }
Ejemplo n.º 25
0
    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));
    }
Ejemplo n.º 26
0
    private void ParseString(
        CommandTreeParserContext context,
        CommandTreeTokenStream stream,
        CommandTree node)
    {
        if (context.State == State.Remaining)
        {
            stream.Consume(CommandTreeToken.Kind.String);
            return;
        }

        var token = stream.Expect(CommandTreeToken.Kind.String);

        // Command?
        var command = node.Command.FindCommand(token.Value, CaseSensitivity);

        if (command != null)
        {
            if (context.State == State.Normal)
            {
                node.Next = ParseCommand(context, node.Command, node, stream);
            }

            return;
        }

        // Current command has no arguments?
        if (!node.HasArguments())
        {
            throw CommandParseException.UnknownCommand(_configuration, node, context.Arguments, token);
        }

        // Argument?
        var parameter = node.FindArgument(context.CurrentArgumentPosition);

        if (parameter == null)
        {
            // No parameters left. Any commands after this?
            if (node.Command.Children.Count > 0 || node.Command.IsDefaultCommand)
            {
                throw CommandParseException.UnknownCommand(_configuration, node, context.Arguments, token);
            }

            throw CommandParseException.CouldNotMatchArgument(context.Arguments, token);
        }

        // Yes, this was an argument.
        if (parameter.ParameterKind == ParameterKind.Vector)
        {
            // Vector
            var current = stream.Current;
            while (current?.TokenKind == CommandTreeToken.Kind.String)
            {
                var value = stream.Consume(CommandTreeToken.Kind.String)?.Value;
                node.Mapped.Add(new MappedCommandParameter(parameter, value));
                current = stream.Current;
            }
        }
        else
        {
            // Scalar
            var value = stream.Consume(CommandTreeToken.Kind.String)?.Value;
            node.Mapped.Add(new MappedCommandParameter(parameter, value));
            context.IncreaseArgumentPosition();
        }
    }
Ejemplo n.º 27
0
 public Handler(CommandTree commandTree, IHelpService helpService)
 {
     _commandTree = commandTree;
     _helpService = helpService;
 }
Ejemplo n.º 28
0
 public ExecuteCommandStage(CommandTree map)
 {
     this.map = map ?? throw new ArgumentNullException(nameof(map));
 }
Ejemplo n.º 29
0
    private string?ParseOptionValue(
        CommandTreeParserContext context,
        CommandTreeTokenStream stream,
        CommandTreeToken token,
        CommandTree current,
        CommandParameter?parameter)
    {
        var value = default(string);

        // Parse the value of the token (if any).
        var valueToken = stream.Peek();

        if (valueToken?.TokenKind == CommandTreeToken.Kind.String)
        {
            var parseValue = true;
            if (token.TokenKind == CommandTreeToken.Kind.ShortOption && token.IsGrouped)
            {
                parseValue = false;
            }

            if (context.State == State.Normal && parseValue)
            {
                // 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))
                            {
                                // Flags cannot be assigned a value.
                                throw CommandParseException.CannotAssignValueToFlag(context.Arguments, token);
                            }
                        }

                        value = stream.Consume(CommandTreeToken.Kind.String)?.Value;
                    }
                    else
                    {
                        // Unknown parameter value.
                        value = stream.Consume(CommandTreeToken.Kind.String)?.Value;

                        // In relaxed parsing mode?
                        if (context.ParsingMode == ParsingMode.Relaxed)
                        {
                            context.AddRemainingArgument(token.Value, value);
                        }
                    }
                }
            }
            else
            {
                context.AddRemainingArgument(token.Value, parseValue ? valueToken.Value : null);
            }
        }
        else
        {
            if (context.State == State.Remaining || context.ParsingMode == ParsingMode.Relaxed)
            {
                context.AddRemainingArgument(token.Value, null);
            }
        }

        // No value?
        if (context.State == State.Normal)
        {
            if (value == null && parameter != null)
            {
                if (parameter.ParameterKind == ParameterKind.Flag)
                {
                    value = "true";
                }
                else
                {
                    if (parameter is CommandOption option)
                    {
                        if (parameter.IsFlagValue())
                        {
                            return(null);
                        }

                        throw CommandParseException.OptionHasNoValue(context.Arguments, token, option);
                    }
                    else
                    {
                        // This should not happen at all. If it does, it's because we've added a new
                        // option type which isn't a CommandOption for some reason.
                        throw new InvalidOperationException($"Found invalid parameter type '{parameter.GetType().FullName}'.");
                    }
                }
            }
        }

        return(value);
    }
Ejemplo n.º 30
0
 public CommandTreeService(CommandTree commandTree)
 {
     this.commandTree = commandTree;
 }