diff --git a/src/Discord.Net.Commands/CommandMap.cs b/src/Discord.Net.Commands/CommandMap.cs index 4343cdd86..76dbd95d3 100644 --- a/src/Discord.Net.Commands/CommandMap.cs +++ b/src/Discord.Net.Commands/CommandMap.cs @@ -9,14 +9,14 @@ namespace Discord.Commands private readonly CommandMap _parent; private readonly string _name, _fullName; - private Command _command; + private readonly List _commands; private readonly Dictionary _items; private bool _isHidden; public string Name => _name; public string FullName => _fullName; public bool IsHidden => _isHidden; - public Command Command => _command; + public IEnumerable Commands => _commands; public IEnumerable SubGroups => _items.Values; /*public IEnumerable SubCommands => _items.Select(x => x.Value._command).Where(x => x != null); public IEnumerable SubGroups => _items.Select(x => x.Value).Where(x => x._items.Count > 0);*/ @@ -27,6 +27,7 @@ namespace Discord.Commands _name = name; _fullName = fullName; _items = new Dictionary(); + _commands = new List(); _isHidden = true; } @@ -48,20 +49,20 @@ namespace Discord.Commands return this; } - public Command GetCommand() + public IEnumerable GetCommands() { - if (_command != null) - return _command; + if (_commands.Count > 0) + return _commands; else if (_parent != null) - return _parent.GetCommand(); + return _parent.GetCommands(); else return null; } - public Command GetCommand(string text) + public IEnumerable GetCommands(string text) { - return GetCommand(0, text.Split(' ')); + return GetCommands(0, text.Split(' ')); } - public Command GetCommand(int index, string[] parts) + public IEnumerable GetCommands(int index, string[] parts) { if (index != parts.Length) { @@ -69,14 +70,14 @@ namespace Discord.Commands CommandMap nextGroup; if (_items.TryGetValue(nextPart, out nextGroup)) { - var cmd = nextGroup.GetCommand(index + 1, parts); + var cmd = nextGroup.GetCommands(index + 1, parts); if (cmd != null) return cmd; } } - if (_command != null) - return _command; + if (_commands != null) + return _commands; return null; } @@ -102,21 +103,26 @@ namespace Discord.Commands nextGroup.AddCommand(index + 1, parts, command); } else - { - if (_command != null) - throw new InvalidOperationException("A command has already been added with this path."); - _command = command; - } + _commands.Add(command); } public bool CanRun(User user, Channel channel) { - if (_command != null && _command.CanRun(user, channel)) - return true; - foreach (var item in _items) + if (_commands.Count > 0) + { + foreach (var cmd in _commands) + { + if (cmd.CanRun(user, channel)) + return true; + } + } + if (_items.Count > 0) { - if (item.Value.CanRun(user, channel)) - return true; + foreach (var item in _items) + { + if (item.Value.CanRun(user, channel)) + return true; + } } return false; } diff --git a/src/Discord.Net.Commands/CommandParser.cs b/src/Discord.Net.Commands/CommandParser.cs index affdc7e2c..c45473f33 100644 --- a/src/Discord.Net.Commands/CommandParser.cs +++ b/src/Discord.Net.Commands/CommandParser.cs @@ -12,13 +12,13 @@ namespace Discord.Commands DoubleQuotedParameter } - public static bool ParseCommand(string input, CommandMap map, out Command command, out int endPos) + public static bool ParseCommand(string input, CommandMap map, out IEnumerable commands, out int endPos) { int startPosition = 0; int endPosition = 0; int inputLength = input.Length; bool isEscaped = false; - command = null; + commands = null; endPos = 0; if (input == "") @@ -52,8 +52,8 @@ namespace Discord.Commands } } } - command = map.GetCommand(); //Work our way backwards to find a command that matches our input - return command != null; + commands = map.GetCommands(); //Work our way backwards to find a command that matches our input + return commands != null; } //TODO: Check support for escaping @@ -78,6 +78,8 @@ namespace Discord.Commands { if (startPosition == endPosition && (parameter == null || parameter.Type != ParameterType.Multiple)) //Is first char of a new arg { + if (argList.Count >= expectedArgs.Length) + return CommandErrorType.BadArgCount; //Too many args parameter = expectedArgs[argList.Count]; if (parameter.Type == ParameterType.Unparsed) { @@ -144,6 +146,7 @@ namespace Discord.Commands } } + //Too few args for (int i = argList.Count; i < expectedArgs.Length; i++) { var param = expectedArgs[i]; @@ -158,11 +161,11 @@ namespace Discord.Commands } } - if (argList.Count > expectedArgs.Length) + /*if (argList.Count > expectedArgs.Length) { if (expectedArgs.Length == 0 || expectedArgs[expectedArgs.Length - 1].Type != ParameterType.Multiple) return CommandErrorType.BadArgCount; - } + }*/ args = argList.ToArray(); return null; diff --git a/src/Discord.Net.Commands/CommandService.cs b/src/Discord.Net.Commands/CommandService.cs index ab24b845d..4340e27a4 100644 --- a/src/Discord.Net.Commands/CommandService.cs +++ b/src/Discord.Net.Commands/CommandService.cs @@ -88,10 +88,10 @@ After: } //Parse command - Command command; + IEnumerable commands; int argPos; - CommandParser.ParseCommand(msg, _map, out command, out argPos); - if (command == null) + CommandParser.ParseCommand(msg, _map, out commands, out argPos); + if (commands == null) { CommandEventArgs errorArgs = new CommandEventArgs(e.Message, null, null); RaiseCommandError(CommandErrorType.UnknownCommand, errorArgs); @@ -99,35 +99,46 @@ After: } else { - //Parse arguments - string[] args; - var error = CommandParser.ParseArgs(msg, argPos, command, out args); - if (error != null) + foreach (var command in commands) { - var errorArgs = new CommandEventArgs(e.Message, command, null); - RaiseCommandError(error.Value, errorArgs); - return; - } - - var eventArgs = new CommandEventArgs(e.Message, command, args); + //Parse arguments + string[] args; + var error = CommandParser.ParseArgs(msg, argPos, command, out args); + if (error != null) + { + if (error == CommandErrorType.BadArgCount) + continue; + else + { + var errorArgs = new CommandEventArgs(e.Message, command, null); + RaiseCommandError(error.Value, errorArgs); + return; + } + } - // Check permissions - if (!command.CanRun(eventArgs.User, eventArgs.Channel)) - { - RaiseCommandError(CommandErrorType.BadPermissions, eventArgs); - return; - } + var eventArgs = new CommandEventArgs(e.Message, command, args); - // Run the command - try - { - RaiseRanCommand(eventArgs); - await command.Run(eventArgs).ConfigureAwait(false); - } - catch (Exception ex) - { - RaiseCommandError(CommandErrorType.Exception, eventArgs, ex); + // Check permissions + if (!command.CanRun(eventArgs.User, eventArgs.Channel)) + { + RaiseCommandError(CommandErrorType.BadPermissions, eventArgs); + return; + } + + // Run the command + try + { + RaiseRanCommand(eventArgs); + await command.Run(eventArgs).ConfigureAwait(false); + } + catch (Exception ex) + { + RaiseCommandError(CommandErrorType.Exception, eventArgs, ex); + } + return; } + var errorArgs2 = new CommandEventArgs(e.Message, null, null); + RaiseCommandError(CommandErrorType.BadArgCount, errorArgs2); } }; } @@ -208,9 +219,19 @@ After: { StringBuilder output = new StringBuilder(); - Command cmd = map.Command; - if (cmd != null) - ShowCommandHelpInternal(cmd, user, channel, output); + IEnumerable cmds = map.Commands; + bool isFirstCmd = true; + if (cmds != null) + { + foreach (var cmd in cmds) + { + if (isFirstCmd) + isFirstCmd = false; + /*else + output.AppendLine();*/ + ShowCommandHelpInternal(cmd, user, channel, output); + } + } else { output.Append('`'); @@ -218,12 +239,12 @@ After: output.Append("`\n"); } - bool isFirst = true; + bool isFirstSubCmd = true; foreach (var subCmd in map.SubGroups.Where(x => x.CanRun(user, channel) && !x.IsHidden)) { - if (isFirst) + if (isFirstSubCmd) { - isFirst = false; + isFirstSubCmd = false; output.AppendLine("Sub Commands: "); } else @@ -235,7 +256,7 @@ After: output.Append('`'); } - if (isFirst) + if (isFirstCmd && isFirstSubCmd) //Had no commands and no subcommands { output.Clear(); output.AppendLine("You do not have permission to access this command."); @@ -246,17 +267,14 @@ After: public Task ShowCommandHelp(Command command, User user, Channel channel, Channel replyChannel = null) { StringBuilder output = new StringBuilder(); - ShowCommandHelpInternal(command, user, channel, output); + if (!command.CanRun(user, channel)) + output.AppendLine("You do not have permission to access this command."); + else + ShowCommandHelpInternal(command, user, channel, output); return _client.SendMessage(replyChannel ?? channel, output.ToString()); } private void ShowCommandHelpInternal(Command command, User user, Channel channel, StringBuilder output) { - if (!command.CanRun(user, channel)) - { - output.AppendLine("You do not have permission to access this command."); - return; - } - output.Append('`'); output.Append(command.Text); foreach (var param in command.Parameters)